用 Ruby 踩踩四人帮

来源:互联网 发布:大兴灭门案 知乎 编辑:程序博客网 时间:2024/06/05 16:27

上上周在书店看到一本《Ruby设计模式》,捡起来 10 分钟看完,扔了(别问我为什么……)
下面用 Ruby 写写设计模式,顺便批一批 Java 和 Gof

1.Factory 和 Abstract Factory

class Factory  attr_accessor :product  def produce    @product.new  endendclass Product  #..endfac = Factory.newfac.product = Productfac.produce

Java写的工厂有这么简单,这么容易重用么?

2.Builder

# 工头class Director  def build_with builderacc = ''[:header, :body, :footer].each do |m|  acc += builder.__send__ m if builder.respond_to? mendacc  endend# 工人class HTMLBuilder  def header; '<html><title>html builder</title>';end  def body;  '<body>html builder</body>'        ;end  def footer; '</html>'                          ;endendclass XMLBuilder  def header; '<?xml version="1.0" charset="utf-8">';end  def body;   '<root>xml builder</root>'            ;endendd = Director.newputs(d.build_with HTMLBuilder.new)puts(d.build_with XMLBuilder.new)

注意:Ruby的工序并不依赖于Builder的类,只要有方法签名就行了。
interface 这种束手束脚,加强耦合的东西完全不需要~

3.Prototype
依样画葫芦。
这里用一点 trick (evil ruby):

require 'evil'class Prototype  # ...endclass Concrete  include Prototype.as_moduleend


4.Adapter
Ruby 包装方法易如反掌:

class Adaptee  def talk; puts 'Adaptee';endendclass Adapter < Adaptee  alias talkee talk  def talkputs 'before Adaptee'talkeeputs 'after Adaptee'  endendAdapter.new.talk

很多没学过设计模式的 Ruby 程序员天天用 adapter……

5.Composite
这个 pattern 是给没有多重继承又没法 mixin 的语言用的。
Ruby 只需要 include module。

6.Decorator

module Colorful  attr_acessor :colorendclass Widgetendw = Widget.new    # w 作为 Widget 的实例,没有 color 方法w.color = 'blue' rescue puts 'w has no color'w.extend Colorful # 现在 w 有 color 方法了w.color = 'blue'puts w.color

可怜的 Java 程序员需要学习设计模式才能写出 decorator。

7.Flyweight

# 重量级对象的瘦身法:如果创建参数相同,则返回同一个对象class FlyweightFactory  class Glyphdef initialize key  @key = key  sleep 1 # 睡一秒,以体现这个对象创建的“重量级”  @square = key ** 2  @cubic = key ** 3endattr_reader :key, :square, :cubic  end  def produce key@glyphs ||= {}    @glyphs[key] || (@glyphs[key] = Glyph.new key)  endendff = FlyweightFactory.newg1 = ff.produce 2g2 = ff.produce 2puts (g1.object_id == g2.object_id)

不得不说 || 是很爽的语法。
另外 Ruby 的 Hash 可以用数组作 key,如果 Glyph 的构造函数需要更多参数,只需要把 produce 里的 key 改成 *key

8.Proxy
Proxy 和 Adapter 的区别只在接口上,它们在 Ruby 中是一样的。
这说明了:1.大道至简; 2.Gof 模式的语言局限性。

9.Chain of Responsibility
如果没有 proc,代码是做不到这么清晰简洁的:

class Chain  def initialize@chain = []  end  def add_handler &block@chain << block  end  def handle req@chain.each do |e|  # 如果handler返回 false(未处理),则让下一个处理  result = e[req]   return result if resultendfalse  endendc = Chain.newc.add_handler {|req| req == 1 ? "1:handled" : puts "1:not my responsibility" }c.add_handler {|req| req == 2 ? "2:handled" : puts "2:not my responsibility" }puts(c.handle 1)puts(c.handle 2)


10.Command
本质:一次调用可以同时执行多个方法。GUI 编程中处理事件很常用。
因为 Java 不能直接传递方法,所以把简单的问题复杂化了……
btw:真不理解 swing 优美在哪里……

class Command  def initialize@executors = []  end  # 另一种方法是让 executors 保存一组对象,每个都带 execute 方法  # ——但是这么简单的事情就需要一组接口,一组实现?  def add_executor &block@executors << block  end  def execute@executors.each {|x| x.call }  endendc = Command.newc.add_executor{ puts 'executor 1' }c.add_executor{ puts 'executor 2' }c.execute

Command 是和 Chain 很相似的东西,可能某天会有人写一本 "Pattern of Patterns" 吧。

11.Template Method
Java 一说模板,C++ 和 Ruby 就笑了。
例(偷懒“重用”一下写过的代码):

# 穷举法检验 de Morgan 定理class Fixnum  %w[a1 a2 a3 b1 b2 b3].each_with_index do |name, idx|    define_method name, do      self & (1<<idx) == 0 ? false : true    end  endend0b1000000.times do |n|  n.instance_eval %q[    if !((a1&&b1) || (a2&&b2) || (a3&&b3)) != !(a1&&b1) && !(a2&&b2) && !(a3&&b3)      puts 'blah'    end  ]end


12.Iterator 和 Visitor
这些模式还是作古吧。
有太多简单的方式进行迭代(map, inject, each, each_with_index,sort ...)
关键点还是语言对泛型和匿名函数的支持。

13.Mediator
将各个类的相互依赖性扔到一个中介类之中。
老老实实的写个中介类?大概会像这样:

class Mediator  def initialize seller, buyer@seller = seller@buyer = buyer  end  def sell@seller.sell  end  def buy@buyer.buy  endend

发现问题了吗? Mediator 出现的根源还是静态类型(是不会推断的那种)带来的耦合。
Duck Typing (check respond_to? instead of class) 早已解耦,根本不需要中介。

14.Strategy
提供运行时选择策略(算法)的可能。
假设 Array 有两种方法:bubble_sort 和 quick_sort
按照 Gof 的教诲,我们可能会这样想:

class Array  def sort optionsif options[:strategy].to_sym == :bubble_sort  bubble_sort()    elsif options[:strategy].to_sym == :quick_sort  quick_sort()end  endendarr.sort :strategy => strategy

根本就是没事找事……看看 Ruby 动态选择调用方法多简单:

Ruby代码
arr.__send__ strategy


15.Singleton

module SingletonClass  class << self# methods  endend

听说有人用两百行实现了严格的 singleton,膜拜中。

结论:
如果没有类型声明和继承,很多依赖性都会消失无踪,接口也无用武之地了。
设计模式大都是 Interface Hack 汇总,枯燥无味、思想僵化、限制创造力,早该下架了。
学设计模式不如学 Ruby Python。
Java 语言(注意不是平台)的弱点导致大量的冗余代码。
所谓从善如流,有功夫写冗余代码不如多写几个测试。
Java 语言(注意不是平台)的历史意义在于:将程序员从过早考虑效率的传统中解放了出来,现在也该功成身退了。