观察者模式
Rails之前有Observer,后来被单独抽离到rails-observer gem中去了。和callback比,observer一般处理model职责之外的行为,比如给用户发邮件。callback更加倾向于处理model职责内的行为,比如验证,默认值等。在我看来,有点像是消息队列,observer订阅/注册某个主题,主题推送通知。此外,观察者模式相对比callback,解耦方面更好些。
装饰器模式
在Python里面很多,比如特性。在Rails里面,是通过委派delegate
来实现的。
Ruby中的include是修改了当前类,或者类的继承链。在我看来,不能够算是装饰器,是因为:
- 不能够多次装饰
- 一般装饰的对象是实例,而不是类
当然,依旧可以用extend
实例的方式去实现,但依旧不能够多次装饰。
下面是用SimpleDelegator
来实现。实际上是通过委派方式,把method在委派给super
。在Rails中,你可以通过delegate
来实现。1 2
require 'delegate'
class Coffee
def cost
2
end
def origin
"Colombia"
end
end
module DecoratorClass
def class
__getobj__.class
end
end
class Milk < SimpleDelegator
include DecoratorClass
def cost
super + 0.4
end
end
class Sugar < SimpleDelegator
include DecoratorClass
def cost
super + 0.2
end
end
p Milk.ancestors # [Milk, DecoratorClass, SimpleDelegator, Delegator, #<Module:0x00007fb5eb8579f8>, BasicObject]
coffee = Coffee.new
Sugar.new(Milk.new(coffee)).cost # 2.6
Sugar.new(Sugar.new(coffee)).cost # 2.4
Milk.new(coffee).origin # Colombia
Sugar.new(Milk.new(coffee)).class # Coffee
单件模式
比较常见的是调用第三方API的client工具,一般只会initial一个实例,这样可以避免多个client导致连接数超多,而且可以复用内存里面已经存在的client。
工厂模式
定义一个用于创建对象的接口,通常为build
,让子类决定实例化哪一个类。工厂方法是一个类的实例化延迟到了子类。比如,创建一个DNS记录,背后的provider有多个的时候,就可以通过这种方式,在创建的时候去判断用哪个类实例化。
适配器模式
可以用于对不同的接口进行包装以及提供统一的接口,或者是让某一个对象看起来像是另一个类型的对象。比较常见的就是ActiveRecord的各种adapter,比如背后支持sql-server, mysql就有不同的adapter。对于ActiveRecord, 只有简单的execute,但是会根据具体的类型,来判断生成什么样的query,如何去连接数据库执行。3
模板模式
个人觉得有点像接口,或者Python中的ABC。基类只声明接口,子类负责具体的实现,没有实现的话,就会调用基类的方法,一般会raise error。
迭代器模式
这个在Ruby里面比较容易实现。通过include Enumerable模块并自定义each method,就可以创建一个迭代器类。下面是一个二叉查找树的例子。
class Bst
include Enumerable
attr_reader :left, :right, :data
def initialize(new_data)
@data = new_data
end
def insert(new_data)
if new_data <= @data
@left ? @left.insert(new_data) : @left = Bst.new(new_data)
else
@right ? @right.insert(new_data) : @right = Bst.new(new_data)
end
self
end
def each(&block)
return to_enum unless block_given?
@left&.each(&block)
yield @data
@right&.each(&block)
self
end
end