2013-04-06 11 views
8

Próbowałem grzebać w double-dispatch pattern i mieć trudny czas. W końcu spróbowałem przykładowego programu, aby pomóc sobie zrozumieć. Here's Istota. Ale potem zdecydowałem się spróbować go i without Double dispatch, a rozwiązanie nie wyglądało bardziej przerażająco niż zwykle. Co ja robię źle?Próba zrozumienia schematu podwójnej wysyłki

Edycja: jak na sugestię, opublikowałem to pytanie here. Trzymaj ten link dla przekierowań.

+0

Możesz mieć więcej szczęścia na http: // http: //programmers.stackexchange.com/. Chociaż jest to interesujące pytanie, nie jest to zbyt dobre dla Stack Overflow; ta strona zazwyczaj preferuje konkretne pytania z "poprawną odpowiedzią". –

+1

Nie zgadzam się; to jest dobre pytanie, które należy zadać pod adresem SO –

Odpowiedz

17

W pojedynczej wysyłce --- to, co widzisz w większości współczesnych języków OO --- metoda jest wysłana w oparciu o typ wykonywalny pojedynczego obiektu. To pokazuje się jako operator kropki (w ruby, java, javascript itp.) Lub operator strzałki (perl, C++).

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

Podwójne wysyłki, wtedy będzie na podstawie typu run-time z dwa obiektów. Jest kilka sposobów na to, że może to wyglądać; i na jakim obiekcie powinna żyć metoda?

# 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 

języków takich jak Groovy, które mają wiele wysyłka uogólniać drugim przykładzie powyżej; biorą pod uwagę parametry czasu wykonywania wszystkie parametry przy wyborze metody do uruchomienia. Zobacz na przykład this blog post o groovy i wielu wysyłek.

Większość nowoczesnych języków OO ma tylko jedną wysyłkę, a wielokrotna wysyłka Wzór jest próbą uzyskania korzyści z wielokrotnej wysyłki do tego języka. Działa nawet w językach dynamicznych, takich jak Ruby. To działa, wykonując pojedynczą wysyłkę dwa razy pod numerem. Pierwsze wywołanie metody wywoła metodę na drugim obiekcie.

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 

Podwójna wysyłka wzór jest to, co ja nazywam wzór niskopoziomowe ponieważ inne wzory są zbudowane na nim. Na przykład wzorzec Odwiedzającego w dużej mierze zależy od wzoru podwójnej wysyłki.


Aktualizacja prostu zobaczyłem swoje GIST. Twój pierwszy sedno naprawdę nie robi podwójnej wysyłki. Oczywiście, wysyłacie dwa razy, ale nie zmieniacie zachowania podczas drugiej wysyłki. Aby zmienić ją na podwójną wysyłkę, zrobiłbym coś takiego.

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

. Myślę, że wzorzec odwiedzającego jest w rzeczywistości powszechnym sposobem realizacji wielu wysyłek. Zobacz np. http://en.wikipedia.org/wiki/Double_dispatch#Double_dispatch_in_C.2B.2B Również twój przykład dentysty może być nieco zagmatwany, ponieważ jest tylko jeden dentysta, więc nie potrzebujesz podwójnej wysyłki. :) – Sarien

+0

@Sarien dobry punkt, dodałem lekarza do przykładu. Tak, odwiedzający to bardzo popularny sposób na podwójną wysyłkę. –

Powiązane problemy