2013-04-06 3 views
8

Я пытаюсь получить double-dispatch pattern и с трудом. Я, наконец, попробовал пример программы, чтобы помочь себе понять. Here's сущность. Но потом я решил попробовать его without Double dispatch, и решение не выглядело более страшным, чем обычно. Что я делаю не так?Попытайтесь понять шаблон двойной отправки

Редактировать: согласно предложению, я разместил этот вопрос here. Сохранение этой ссылки для перенаправления.

+0

Возможно, вам удастся на http: // http: //programmers.stackexchange.com/. Хотя это интересный вопрос, это не очень подходит для Stack Overflow; этот сайт, как правило, предпочитает конкретные вопросы с «правильным ответом». –

+1

Я не согласен; это прекрасный вопрос, заданный на SO –

ответ

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, которые имеют множественную отправку, обобщают второй пример выше; они рассматривают типы времени выполнения всех параметров при выборе способа запуска. См. Например, 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 

двойной диспетчерская шаблон является то, что я называю шаблон низкого уровня, так как другие модели построены на нем. Например, шаблон посетителя в значительной степени зависит от шаблона двойной отправки.


Update Только видел ваши гов. Ваш первый смысл не делает двойную отправку. Конечно, вы отправляете дважды, но вы не меняете поведение во второй отправке. Чтобы изменить его на двойную отправку, я бы сделал что-то вроде этого.

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

+0

@ Сариен хороший момент, я добавил врача к примеру. Да, посетитель - очень распространенный способ сделать двойную отправку. –

Смежные вопросы