在动态语言中实现访问者模式的首选方法?

发布于 2024-07-04 22:56:44 字数 759 浏览 7 评论 0原文

作为我自己的练习,我正在将示例程序翻译成各种语言。 从 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

或者动态语言中是否有另一种首选的习惯用法?

As an exercise for myself, I was translating a sample program into various languages. Starting in C#, I had a visitor-pattern interface like so:

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

Moving to ruby (or python, or whatever), I no longer get dispatch from the compiler based on type. Should I do the dispatch in the visitor itself?

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

  ...

Or should I do the dispatch in the different specializaions of the room:

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

Or is there another preferred idiom that is used in dynamic languages?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

悲念泪 2024-07-11 22:56:51

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

I would go with the second version. The first one looks like the kind of code smell that Visitor is supposed to solve: long if-else-if or switch-case statements.

你另情深 2024-07-11 22:56:50

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

在 Ruby 中,你可以尝试

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

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

My recommendation is to use the former approach. There are pluses and minuses for each approach. The former is harder to maintain as the number of Room types grows; the latter is harder as the number of Cleaner types grows.

In Ruby, you could try

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

PS: not all dynamically typed languages are unable to do dispatch based on type; some can infer type, or failing that, can used forced casting to pick the proper method among the overloaded options.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文