我一直试图找到double-dispatch pattern并且很难过。我终于尝试了一个示例程序来帮助自己理解。 Here's要点。但后来我决定尝试without Double dispatch并且解决方案看起来并不比平常更糟糕。我做错了什么?
修改:根据建议,我发布了此问题here。保持此链接的重定向。
答案 0 :(得分:18)
在单一调度中 - 您在大多数现代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等语言概括了上面的第二个例子;在选择要运行的方法时,他们会考虑所有参数的运行时类型。例如,请参阅this blog post关于groovy和多次发送的信息。
大多数现代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)