论坛首页 编程语言技术论坛

Design patterns in ruby系列之---strategy模式

浏览 2918 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (1) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-07-31  
strategy模式,对java有一定了解的JE友,都应该熟悉,这里不作过多的介绍.
下面是ruby版本的strategy模式体现,参考Head first design 设计模式中文版本第一章策略模式.由于ruby相对于java的不同,没有了接口的概念,也没有抽象类的概念,但是我闷可以变相的实现抽象和接口的应用,在ruby中
#
#鸭子抽象类
class Duck
  attr_accessor :fly_behavior, :quack_behavior 
  
  def display
    raise "this is a abstract method"
  end
  
  def perform_fly
    if fly_behavior.is_a?(FlyBehavior)
      fly_behavior.fly
    end
  end
  
  def perform_quack
    if quack_behavior.kind_of?(QuackBehavior) 
      quack_behavior.quack
    end
  end
end

#
#具体鸭子类
class MallarDuck < Duck
  def initialize
    @fly_behavior = FlyWithWings.new
    @quack_behavior = Quack.new
  end
  
  def display
    puts "I'm a real Mallard duck"
  end
end

#
#具体鸭子类
class ModelDuck < Duck
  def initialize
    @fly_behavior = FlyNoWay.new
    @quack_behavior = Quack.new
  end
  
  def display
    puts "I'm a real Model duck"
  end
end

#
#抽象类,具体方法让子类去实现
class FlyBehavior
  def fly
    raise "Abstract method call"
  end
end

class QuackBehavior
  def quack
    raise "Abstract method call"
  end
end

#
#实现抽象类行为的子类
class FlyWithWings < FlyBehavior
  def fly
    puts "I'm flying!!!"
  end
end

class FlyNoWay < FlyBehavior
  def fly
    puts "I can't fly!!"
  end
end

class FlyRocketPowered < FlyBehavior
  def fly
    puts "I'm flying with a rocket"
  end
end

class Quack < QuackBehavior
  def quack
    puts "Quack!!!"
  end
end

#
#测试方法
require 'benchmark' 
puts "strategry pattern start!!!"
mallard = MallarDuck.new
mallard.display
mallard.perform_fly
mallard.perform_quack

modeld = ModelDuck.new
modeld.display
modeld.perform_fly
modeld.fly_behavior = FlyRocketPowered.new
modeld.perform_fly



输出---------------------
strategry pattern start!!!
I'm a real Mallard duck
I'm flying!!!
Quack!!!
I'm a real Model duck
I can't fly!!
I'm flying with a rocket

多多交流谢谢!
   发表时间:2008-07-31  
另外一个例子,设计到排序算法[系转载]
#
# The GoF Strategy pattern
# written by Matthieu Tanguay-Carel
#
# Sorter is the Context object. It allows to choose between sorting
# implementations.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
class QuickSort
  def sort arr
    return [] if arr.length == 0
    x, *xs = *arr
    smaller, bigger = xs.partition{ |other| other < x }
    sort(smaller) + [x] + sort(bigger)
  end
end

class MergeSort
  def sort array
    if array.length <= 1
      return array
    end
    middle = array.length / 2
    left = array[0...middle]
    right = array[middle...array.length]
    left = sort left
    right = sort right
    return merge(left,right)
  end
  
  def merge left,right
    result = []
    while left.length > 0 and right.length > 0
      left.first <= right.first ? result << left.shift : result << right.shift
    end
    result.push(*left) if left.length > 0
    result.push(*right) if right.length > 0
    return result
  end
end

class Sorter
  @@default_strategy = QuickSort.new
  def self.sort arr, strategy=nil
    strategy ||= @@default_strategy
    strategy.sort(arr)
  end
end

def print_elems arr
  arr.each {|elem| $stdout.write "#{elem} "}
  puts ''
end
def get_random_array size
  arr = []
  size.times do arr << rand(100) end
  arr
end

require 'benchmark'
#if __FILE__ == $0
  arr_length = 1000
  arr1 = get_random_array arr_length
  puts "Sorting first array"
  #print_elems arr1
  puts "Time taken for QuickSort: #{Benchmark.measure {
    arr1 = Sorter.sort(arr1, QuickSort.new)
    print_elems arr1[0...40]
  }}"
  puts "\nSorting second array"
  arr2 = get_random_array arr_length
  #print_elems arr2
  puts "Time taken for MergeSort: #{Benchmark.measure {
    arr2 = Sorter.sort(arr2, MergeSort.new)
    print_elems arr2[0...40]
  }}"
#end
0 请登录后投票
   发表时间:2008-07-31  
我用了近1年的ruby,可能是由于没有开发过所谓的“大系统”,我发现:

很少会用设计模式。

我会经常用ruby的闭包,mix-in特性来解耦。

还有一些内小的class,最多200行。

0 请登录后投票
   发表时间:2008-07-31  
dazuiba 写道
我用了近1年的ruby,可能是由于没有开发过所谓的“大系统”,我发现:

很少会用设计模式。

实际上很多“经典的”面向对象设计模式之所以存在只是为了克服C++/JAVA/C#的一切固有的设计缺陷想出来的workaround
照搬到Ruby里面就是脱了裤子放屁
比如说楼主的这个鸭子的例子…哎,还不要说Ruby了,哪怕你是用Java,我怎么就看不出来MallarDuck和ModelDuck这两个子类存在的价值是什么呢?行为的差异已经抽到strategies里面去了,就为了表达两个字符串的差异就创建出两个子类,我怎么就不理解这个设计到底优雅在哪儿呢?
至于这个sort的例子,sigh,真的,只能说惨不忍睹啊
(很多时候我想对一些年轻程序员说,你们别再看什么设计模式了。你们用用脑子,睁开眼睛,去看看系统里哪些东西在变化,哪些东西保持不变,哪些地方有重复代码,哪些设计是脱了裤子放屁。)
3 请登录后投票
   发表时间:2008-07-31  
100行ruby代码能干不少事呢,在提倡节约型社会的年代,楼主显得太浪费了。
非要弄那么多类,居然还要有抽象类,太过份了。方法级别的组合加上duck typing原则就够了,第一个例子玩花样可以用用forwardable/delegate,或者花几行代码搞个DSL。
0 请登录后投票
   发表时间:2008-07-31  
我看这个帖子标题后就在想,好像怎么想也想不出来ruby里面用这个设计模式该怎么玩,有没有必要玩,然后看完帖子之后,才发现,确实是“脱裤子放屁--多此一举”,呵呵
0 请登录后投票
   发表时间:2008-07-31  
这个,lz,没有打击你的意思,我没想到有什么好处啊……
为什么我觉得这纯粹是用java的方法来写ruby应用呢?
0 请登录后投票
   发表时间:2008-08-01  
只能说,你了解了 Java 中 Strategy 的目的,但是有必要在 Ruby 中再现这种模式么?感觉很迂腐,为了设计而设计。

做开发始终要记住,设计是为了达到某个目的。既然 Ruby 提供如此多的特性,根本就不需要这么多的模式。Duck Typing,Mix-In,等等,都比照抄 Java 的设计模式强得多。用所谓的设计模式把事情复杂化,就是和自己过不去。
0 请登录后投票
   发表时间:2009-06-04  
你还不了解ruby,不要把他当java用。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics