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

用 Ruby 踩踩四人帮

浏览 36670 次
该帖已经被评为精华帖
作者 正文
   发表时间:2009-04-23  
现在一些年轻人的习惯很不好,非要通过批驳另一个东西的方式,来表达自己很喜欢这个东西的情感。
你喜欢就喜欢吧,干嘛非得说人家多么多么不好,更何况Java也远没有那么不堪嘛,没有Java,何来JavaEye呢,不是一个层面的东西非得搁一块说。

帖子还是可以,就是搞不懂为什么你会说Proxy和Adapter是一样的,说明Gof的局限性云云,Visitor如果真的已经作古,那就见鬼了,都不知道要如何去实现一个消息传递机制。学设计模式不如学 Ruby Python……唉,但愿不会有人听你的。

还是那句话,你喜欢就喜欢吧,干嘛非得把别人家大骂一通才舒坦?更何况骂的也不对,只让人感觉到年少轻狂,经历过的项目还不够大。
0 请登录后投票
   发表时间:2009-04-24  
所有这些OO设计模式的目的只是为了遵循那11个基本的OO设计原则,虽然动态语言在编码上不需要参考这些设计,不了解他们你也可能编码很好,给你一个功能你可以实现的很漂亮,但如果希望在全局项目上把握架构,学习这些设计模式还是很有意义的,其实就是一种共性的解决问题的思维方式。

这篇文章当做IT八卦还可以看看,若是当真可是有误人子弟之嫌,LS说的很对,"学设计模式不如学 Ruby Python……唉,但愿不会有人听你的。"
0 请登录后投票
   发表时间:2009-04-24   最后修改:2009-04-24
yelm 写道
就是搞不懂为什么你会说Proxy和Adapter是一样的

在 java 和 C++中,proxy 使用原接口,adapter 不使用原接口。我说的是 ruby 中没区别,因为 ruby 没有也不需要接口。当然你也可以用继承来模拟接口,那就是脱离实际,为模式而模式了。

yelm 写道
Visitor如果真的已经作古,那就见鬼了

Hal Fulton 写道
Well-known examples of these are given elsewhere; the Visitor pattern is essentially implemented in Ruby's default iterator each, and other patterns are part of Ruby's standard distribution (the standard libraries delegator.rb and singleton.rb).


和善的人们把这个叫做 visitor:
[1..10].each{|e| puts e }

why? 无非是传了一个函数而已。能传函数的语言的出现比设计模式早多了。
既然能直接传递 "visit",干嘛还用 "visitor" 携带 "visit" ? 在 ruby 中根本就是没必要的概念。
0 请登录后投票
   发表时间:2009-04-24  
lllyq 写道
但如果希望在全局项目上把握架构,学习这些设计模式还是很有意义的,其实就是一种共性的解决问题的思维方式。

建议看看玻利亚《怎样解题》。

另:真正共性的解决问题方式在代数中。
0 请登录后投票
   发表时间:2009-04-28  
晕。批JAVA设计模式与GOF我认为完全没有这个必要。

毕竟3者不能拿来比。
0 请登录后投票
   发表时间:2009-04-29  
年轻人,要是自己没到一定水平不要乱批。
你觉得你比James Gosling 更聪明的时候再去批吧。
0 请登录后投票
   发表时间:2009-04-30  
实在好奇得狠,楼上张口闭口年轻人的诸位先贤,究竟贵庚几何,写过多少代码,经历过多大的项目。
0 请登录后投票
   发表时间:2009-04-30  
oCameLo 写道
实在好奇得狠,楼上张口闭口年轻人的诸位先贤,究竟贵庚几何,写过多少代码,经历过多大的项目。

看看lss都转了一些什么贴就知道了:
引用

JSP里request变量列表
Java正则表达式入门
update多列的几种选择
常用正则表达式
File用法
java.lang.OutOfMemoryError解决办法

注:是转的...
0 请登录后投票
   发表时间:2009-04-30  
干嘛非要拿Java来踩呢?直接拿C或者拿汇编来踩,不是踩的更痛快?

喜新厌旧有时候不是什么好事,看看蓝色巨人的产品,全是Ruby写的吗?全身Java写的吗?全是C/C++写的吗?
一个软件帝国,是一行代码一行代码积累起来的,不是哪个新技术创造出来的。

再说如果有才的话,也可以搞一个新的语言,回来把Ruby批一通。

不过几个例子写的挺好,恩。
0 请登录后投票
   发表时间:2009-05-01  
周末正好有空。
既然大家都这么扯了,那我就胡扯一下吧。
引用

1.Factory 和 Abstract Factory
Ruby代码  

class Factory
  attr_accessor :product
  def produce
    @product.new
  end
end
class Product
  #..
end
fac = Factory.new
fac.product = Product
fac.produce

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


在spring流行之前,工厂模式倒是最简单组织JAVA对象创建的一种方式,工厂更多的是个容器,
顺便一说,工厂类通常是使用静态方法创建对象,网上找得到得例子都是玩具,你和玩具较什么劲。
实际生产中采用工厂模式,是因为要创建的类太多,不好记忆,所以归类放在工厂类。而且也容易分工,什么开发人员负责哪类对象。
要做一个可重用的万能工厂纯粹是脑子进水的想法。业务类别的工厂方法,基本上项目结束就扔。
有了轻量级容器之后。工厂模式鸡肋了。

引用

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

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


面向对象的角度来说,工头是不会替工人干活的。每个工人自己准备一个输出方法toInfoString(),
工头为了便于管理,会指定工人必须实现Info接口,接口只有一个方法toInfoString()。
指定接口并不是束手束脚,放在公司开发团队层面是有效的管理手段,可以分配具体实现工作给不同的队员。而且最后测试也方便,通常测试接口即可。

引用

3.Prototype
依样画葫芦。
这里用一点 trick (evil ruby):
Ruby代码
 
require 'evil'
class Prototype
  # ...
end
class Concrete
  include Prototype.as_module
end


说实在,写了几年JAVA没实现几个Cloneable。或者说没遇到创建大量相同对象副本的场景(除了实现历史记录、undo redo这类需求)。
似乎jakata commons还有一些反射小工具可以做这些事。更倾向于使用singlton,用得多的干脆new,或者几个标准工厂方法,策略模式的。
写一次基本OK了。况且这些场景不多。(除非是得罪老板被派去写GUI)

引用

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

class Adaptee
  def talk; puts 'Adaptee';end
end
class Adapter < Adaptee
  alias talkee talk
  def talk
puts 'before Adaptee'
talkee
puts 'after Adaptee'
  end
end
Adapter.new.talk

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


都AOP了。写个简单的拦截对象(spring 2.0好像只要参数对上号就好),容器配配就完事,还整这出,要拦截也的拦截一堆对象吧?

引用

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


据我的经验,通常是早期对象设计得不好,项目到后期重构难度大才需要Composite。不过现在的IDE重构功能强大。
况且IoC方式下做开发,基本多余。。
引用

6.Decorator
Ruby代码

module Colorful
  attr_acessor :color
end
class Widget
end
w = 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。


据我所知,java程序员除了刚毕业的,基本上都没这么土,依赖注入基本上都是标配了。直接就用原生对象,还费什么劲去修饰(decorate)它?
敢情Ruby程序员都认为Java程序员不用IDE得?重构一下再把红X的地方修改一下,老板语:瞎忙活什么。IOC的好处就是在对象中声明要用到的资源对象,编写代码的时候不用考虑其来源。
配置一下或者autowire或annotation一下拉倒。结果大大降低复杂度,设计也更扁平化。设计不够合理?没关系,还有AOP嘛。

引用

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


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


JAVA在推行Pojo和Ioc这对兄弟,都轻量级。通常都不设计重量级对象,假设非要重量级对象,也只是选择部分耗时耗内存而又线程独占的对象进行池化。通常也只是容器上配置。

引用

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


proxy模式在解决一些DEBUG问题中有独特的作用。通常AOP可以替代之,只有一些上了线的老旧项目修改麻烦,会用得比较多,通常也是动态代理和反射来解决,只要不是性能瓶颈。

引用

9.Chain of Responsibility
如果没有 proc,代码是做不到这么清晰简洁的:
Ruby代码
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 result  
    end 
    false 
  end     
end 
c = Chain.new 
c.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)
 

Java匿名类的用法大把的。况且有IOC得小糖,谁会用链条(Chain)自己锁自己?

引用

10.Command
本质:一次调用可以同时执行多个方法。GUI 编程中处理事件很常用。
因为 Java 不能直接传递方法,所以把简单的问题复杂化了……
btw:真不理解 swing 优美在哪里……
Ruby代码
class Command  
  def initialize  
    @executors = []  
  end 
  # 另一种方法是让 executors 保存一组对象,每个都带 execute 方法  
  # ——但是这么简单的事情就需要一组接口,一组实现?  
  def add_executor &block  
    @executors << block  
  end 
  def execute  
    @executors.each {|x| x.call }  
  end 
end 
c = Command.new 
c.add_executor{ puts 'executor 1' }  
c.add_executor{ puts 'executor 2' }  
c.execute 

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


不知道诸位知道不知道(这句话有艺术吧O(∩_∩)O)JDK5有个Executors可以方便创建线程池,spring也有个TheadPoolExecutor。
配置一下,然后把Command用Runnable或者Callable包装一下往里面扔。

引用

11.Template Method
Java 一说模板,C++ 和 Ruby 就笑了。
例(偷懒“重用”一下写过的代码):
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 
  end 
end 
0b1000000.times do |n|  
  n.instance_eval %q[  
    if !((a1&&b1) || (a2&&b2) || (a3&&b3)) != !(a1&&b1) && !(a2&&b2) && !(a3&&b3)  
      puts 'blah' 
    end 
  ]  
end 


个人认为,少数情况,万能模板和永动机也就一回事,真的还不如FP。赞成接口和抽象类有点作用的请举手。。。当我没说。。。。

引用

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


相信没人写JAVA 仍不用IDE 那么前卫了吧。那么前卫,我甘拜下风。
打个for,按下辅助键。
打个switch,按下辅助键。
至于Visitor能避免则避免,少用,没什么经验,至少没碰上费用Visitor解决不了的场景。

引用

13.Mediator
将各个类的相互依赖性扔到一个中介类之中。
老老实实的写个中介类?大概会像这样:
Ruby代码
class Mediator  
  def initialize seller, buyer  
    @seller = seller  
    @buyer = buyer  
  end 
  def sell  
    @seller.sell  
  end 
  def buy  
    @buyer.buy  
  end 
end 

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


重复上面的话:都IoC了。。。。 省略50个字。

引用

14.Strategy
提供运行时选择策略(算法)的可能。
假设 Array 有两种方法:bubble_sort 和 quick_sort
按照 Gof 的教诲,我们可能会这样想:
Ruby代码
class Array 
  def sort options  
    if options[:strategy].to_sym == :bubble_sort 
      bubble_sort()  
    elsif options[:strategy].to_sym == :quick_sort 
      quick_sort()  
    end 
  end 
end 
arr.sort :strategy => strategy 

根本就是没事找事……看看 Ruby 动态选择调用方法多简单:
Ruby代码
arr.__send__ strategy 


实际开发环境,少用策略模式,因为每个策略都有个名字或者类,太多了记不住头晕。现在Java大力推行POJO和IoC,虽说不是万能药,但分工合作的情况下少用“策略”模式。
最好是打个点“.”就能出来的方法。

引用

15.Singleton
Ruby代码
module SingletonClass  
  class << self 
    # methods  
  end 
end 

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


有这么复杂?IoC的配置下,想singleton就singleton,想pool object就pool object。想每次都创建新对象也行。
就算我是用不起IoC的穷酸。也可以写个加锁的静态方法的。

结论:

我还是去火星圈继续扯吧。
7 请登录后投票
论坛首页 编程语言技术版

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