3

作为我自己的练习,我正在将一个示例程序翻译成各种语言。从 C# 开始,我有一个访问者模式界面,如下所示:

interface Visitor
    {
        void Accept(Bedroom x);
        void Accept(Bathroom x);
        void Accept(Kitchen x);
        void Accept(LivingRoom x);
    }

转向 ruby​​(或 python,或其他),我不再根据类型从编译器获得调度。我应该在访客本身中进行调度吗?

class Cleaner

  def accept(x)
    acceptBedroom(x) if Bedroom === x
    acceptBathroom(x) if Bathroom === x
    acceptKitchen(x) if Kitchen===x
    acceptLivingRoom(x) if LivingRoom===x
  end

  ...

或者我应该在房间的不同专业中进行调度:

class Bathroom<Room
  def initialize(name)
    super(name)
  end
  def accept(visitor)
    visitor.acceptBathroom(self)
  end
end

或者是否有另一个在动态语言中使用的首选习语?

4

2 回答 2

3

我的建议是使用前一种方法。每种方法都有优点和缺点。随着房间类型数量的增加,前者更难维护;随着清洁器类型数量的增加,后者更难。

在 Ruby 中,您可以尝试

def accept(x)
  send "accept#{x.class}".to_sym, x
end

PS:并不是所有的动态类型语言都不能基于类型进行调度;有些人可以推断类型,或者如果失败,可以使用强制转换在重载选项中选择正确的方法。

于 2008-09-04T19:31:52.880 回答
3

我会选择第二个版本。第一个看起来像是 Visitor 应该解决的那种代码异味:长 if-else-if 或 switch-case 语句。

于 2008-09-04T20:03:27.860 回答