2013-04-06 25 views
8

我一直在努力训练double-dispatch pattern并且很难。我终于尝试了一个示例程序来帮助我理解。 Here's的要点。但后来我决定尝试一下without Double dispatch,解决方案看起来不像平常那​​么糟糕。我究竟做错了什么?尝试了解双派遣模式

编辑:根据建议,我已发布此问题here。保持此链接重定向。

+0

您可能对http:// http://programmers.stackexchange.com/有更好的运气。虽然这是一个有趣的问题,但它不太适合Stack Overflow;本网站倾向于选择具有“正确答案”的具体问题。 – 2013-04-06 01:23:39

+1

我不同意;在SO – 2013-04-06 04:12:30

回答

17

在单个调度---你在大多数现代OO语言中看到---一种方法是根据单个对象的运行时类型调度。这显示为点运算符(在ruby,java,javascript等)或箭头运算符(perl,C++)。

# look, ma single dispatch! 
# method on obj's run-time type that is called 
dentist.work_on(patient) 

双调度,然后,将基于对象的运行时类型。这看起来有几种方式;该方法应该活在哪个对象上?

# Hmm, this looks weird. 
# Is the method in to dentist.class or patient.class? 
(dentist, patient).do_dentistry() 


# okay, this looks more familiar; the method lives on obj1.class 
# This only works in static-typed languages which support double dispatch 
# in which you declare the type of the method parameters. 
dentist.work_on(patient) 

class Dentist 
    def work_on(Adult patient); ...; end 
    def work_on(Child patient); ...; end 
end 

像groovy这样的语言有多个调度概括上面的第二个例子;他们在选择运行哪种方法时考虑所有参数的运行时类型。有关groovy和多次调度,请参阅this blog post

大多数现代OO语言只有单个派遣和多派遣派遣模式是试图获得多种派遣语言的好处。它甚至适用于像Ruby这样的动态语言。它通过连续执行单个调度两次而工作。第一个方法调用将调用第二个对象的方法。

class Dentist 
    def work_on(patient) 
     patient.dispatch_work(self) 
    end 
    def work_on_adult(patient) 
     drill_as_hard_as_you_can(patient) 
    end 
    def work_on_child(patient) 
     use_bubble_gum_toothpaste(patient) 
     give_toothbrush_to(patient) 
    end 
end 

class Doctor 
    def work_on(patient) 
     patient.dispatch_work(self) 
    end 
    def work_on_adult(patient) 
     do_checkup(patient) 
    end 
    def work_on_child(patient) 
     assure_presence_of(patient.guardian) 
     ask_questions_to(patient.guardian) 
     do_checkup(patient) 
     give_cheap_toy_to(patient) 
    end 
end 



class Adult 
    def dispatch_work(dentist) 
     dentist.work_on_adult(self) 
    end 
end 

class Child 
    def dispatch_work(dentist) 
     dentist.work_on_child(self) 
    end 
end 

双重派遣模式就是我所说的一个低级别的模式,因为其他的模式是建立在它。例如,访问者模式严重依赖于双重调度模式。


更新只看见自己的要旨。你的第一要义并不是真的在做双重调度。当然,你要派遣两次,但你并没有改变第二次派遣的行为。把它改成双派遣我会做这样的事情。

class Chicken 
    def make_dispatch dish 
    dish.make_with_chicken self 
    end 
end 

class Beef 
    def make_dispatch dish 
    dish.make_with_beef self 
    end 
end 


module Dish 
    def make meat 
    meat.make_dispatch self 
    end 
end 

class Sandwich 
    include Dish 

    def make_with_chicken chicken 
    puts "Grilled Chicken Sandwich" 
    end 

    def make_with_beef beef 
    puts "Roast Beef Sandwich" 
    end 
end 

class Stew 
    include Dish 

    def make_with_chicken chicken 
    puts "Thai curry" 
    end 

    def make_with_beef beef 
    puts "Beef stew" 
    end 
end 

class Casserole 
    include Dish 

    def make_with_chicken chicken 
    puts "Chicken Pot Pie--or something" 
    end 

    def make_with_beef beef 
    puts "Shepard's Pie" 
    end 
end 

Sandwich.new.make(Chicken.new) 
Stew.new.make(Chicken.new) 
Casserole.new.make(Beef.new) 
+0

处询问这是一个很好的问题我认为访问者模式实际上是一种实现多次调度的常用方式。见例如http://en.wikipedia.org/wiki/Double_dispatch#Double_dispatch_in_C.2B.2B同样你的牙医例子可能有点混乱,因为只有一名牙医,所以你不需要双重派遣。 :) – Sarien 2013-04-06 08:00:04

+0

@Sarien好点,我已经增加了一个医生的例子。是的,访客是一种非常常见的双重派遣方式。 – 2013-04-06 09:31:18