design patterns in ruby 读书笔记

书里让我脑残的文法:
But Ruby programs do not crash with any-
thing like the frequency that you might expect given the lengths that statically typed
languages go to in to avoid even the remote poss
ibility of type errors.
我怀疑自己的英语是不是退步太多了...Orz

开篇总结思想:
隔离变化的和不变的
对接口编程
组合优于继承
用委托

然后讲具体的pattern:
template method讲的是一个类,abstract method(hook method)占位,
这个父类派生出一堆具体的子类用concrete method来填充那些方法
但是这个模式是基于继承的,依赖父类不太好
于是讲到用委托,把那些concrete method封装到一个个单独的类里面
这个就叫strategy,template是通过选一个子类来选择具体的方案,strategy是选一个策略类...
ruby这里的动态绑定优势就是如果用stragegy方法,不需要一个基类了...
class Report
 attr_reader :title, :text
 attr_accessor :formatter
 def output_report()
 @formatter.output_report(self)
 end
end

class PlainTextFormatter
 def output_report(context)
   puts("***** #{context.title} *****")
 end
end

更进一步,ruby能传block...简单情况下class都不用写了...
比如
a = ['russell', 'mike', 'john', 'dan', 'rob']
a.sort{|a,b|a.length<=>b.length}

其实就是传递了一个代码块作为一个strategy,因为ruby语法层面的支持显得"呼吸一样"自然
本来java之类的写法应该是
lengthStragegy extends abstractStrategy{
 blablabla;
 ...
}
a = new sort();
a.setStrategy(lengthStragegy);
a.sort(data);

30%的文章就讲了以上这么一点点...老外的书有点絮絮叨叨碎碎念...

observer...就是在建立一个需要监听的队列,每次有修改就通知他们...
比如每次更改薪水的时候...通知observer队列...
def salary=(new_salary)
 @salary = new_salary
 notify_observers
end
def notify_observers
 @observers.each do |observer|
 observer.update(self)
end

但是如果把observer作为继承得到的一个特性就不好了,
ruby可以用module mixin...结果就是这样:
--------------------------------
require 'observer'
class Employee
 include Observable
 attr_reader :name, :address
 attr_reader :salary
 def initialize( name, title, salary)
   @name = name
   @title = title
   @salary = salary
 end
 def salary=(new_salary)
   @salary = new_salary
   changed
   notify_observers(self)
 end
end

class Bb
 def update(b)
   puts 'get update'
 end
end

a = Employee.new('22','33',44)
c = Bb.new
a.add_observer(c)
a.salary=22

接下来讲到observer通知多个事件的处理方法:
fred.salary = 1000000
fred.title = 'Vice President of Sales'
# Now inform the observers!
fred.changes_complete
这算是一组事件完成后给一个notify而不是单个事件完成就通知...

然后是component方法...用于处理有相似行为特征的树形结构...
class Task
 attr_reader :name
 def initialize(name)
   @name = name
 end
 def get_time_required
   0.0
 end
end

class MakeBatterTask < Task
 def initialize
   super('Make batter')
   @sub_tasks = []
   add_sub_task( AddDryIngredientsTask.new )
   add_sub_task( AddLiquidsTask.new )
   add_sub_task( MixTask.new )
 end
 def add_sub_task(task)
   @sub_tasks << task
 end
 def remove_sub_task(task)
   @sub_tasks.delete(task)
 end
 def get_time_required
   time=0.0
   @sub_tasks.each {|task| time += task.get_time_required}
   time
 end
end

然后是iterator...这个在ruby中相当容易
[3,4,5].each{|i| xxx}
如果要让一个类也有each的方法,只要mixin enumerable module:
class Portfolio
 include Enumerable
 def initialize
   @accounts = []
 end
 def each(&block)
   @accounts.each(&block)
 end
 def add_account(account)
 @accounts << account
 end
end
a = Portfolio.new
a.add_account(2)
a.add_account(3)
a.each{|i|puts i}
这里讲到interator的常见问题是迭代过程中如果删除一个元素,会漏掉一个...
array=['red', 'green', 'blue', 'purple']
array.each do | color |
 puts(color)
 array.delete(color) if color == 'green'
end
输出是:
red
green
purple(漏掉了一个...)
...书中提出的一个解决办法是初始化的时候复制一份原来的array...

然后是command...
这里讲到了一个design pattern滥用的问题
class FileDeleteCommand
 def initialize(path)
   @path = path
 end
 def execute
   File.delete(@path)
 end
end
fdc = FileDeleteCommand.new('foo.dat')
fdc.execute
其实以上只要一句话File.delete('foo.dat')....用了command反而繁琐...

 

你可能感兴趣的:(编程,读书,Ruby,Go)