2013-04-06 30 views
8

Tôi đã cố gắng để grok các double-dispatch pattern và gặp khó khăn. Cuối cùng tôi đã thử một chương trình mẫu để giúp bản thân mình hiểu. Here's ý chính. Nhưng sau đó tôi quyết định thử nó without Double dispatch và giải pháp trông không tệ hơn bình thường. Tôi đang làm gì sai?Cố gắng hiểu mô hình công văn kép

Chỉnh sửa: theo đề xuất, tôi đã đăng câu hỏi này here. Giữ liên kết này xung quanh để chuyển hướng.

+0

Bạn có thể có may mắn hơn trên http: // http: //programmers.stackexchange.com/. Trong khi đây là một câu hỏi thú vị, nó không thực sự phù hợp cho Stack Overflow; trang web này có xu hướng thích các câu hỏi cụ thể hơn với "câu trả lời đúng". –

+1

Tôi không đồng ý; đây là một câu hỏi hay để hỏi tại SO –

Trả lời

17

Trong một công văn --- những gì bạn thấy trong hầu hết các ngôn ngữ OO hiện đại --- một phương pháp là được gửi dựa trên loại thời gian chạy của một đối tượng duy nhất. Điều này hiển thị dưới dạng toán tử dấu chấm (trong ruby, java, javascript, v.v.) hoặc toán tử mũi tên (perl, C++).

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

văn đôi, sau đó, sẽ dựa vào loại thời gian chạy của hai đối tượng. Có một vài cách mà điều này có thể xem xét; và phương pháp nào nên sống?

# 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 

Các ngôn ngữ như ngôn ngữ có nhiều công văn tổng quát ví dụ thứ hai ở trên; họ xem xét các loại thời gian chạy là tất cả thông số khi chọn phương thức nào để chạy. Xem ví dụ this blog post về groovy và nhiều công văn.

Hầu hết các ngôn ngữ OO hiện đại chỉ có một công văn và nhiều công văn mẫu là một nỗ lực để nhận được lợi ích của nhiều công văn sang ngôn ngữ. Nó thậm chí hoạt động cho các ngôn ngữ động như ruby. Nó hoạt động bằng cách thực hiện một công văn hai lần liên tiếp. Cuộc gọi phương thức đầu tiên sẽ gọi một phương thức trên đối tượng thứ hai.

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 

Công văn đôi mẫu là cái mà tôi gọi một mô hình cấp thấp vì mô hình khác được xây dựng trên đó. Ví dụ: mẫu Khách truy cập dựa nhiều vào mẫu công văn kép.


Cập nhật Chỉ cần thấy GIST của bạn. Gist đầu tiên của bạn không thực sự làm công văn kép. Chắc chắn, bạn đang gửi đi hai lần, nhưng bạn không thay đổi hành vi trong lần gửi thứ hai đó. Để thay đổi nó thành công văn kép, tôi sẽ làm một cái gì đó như thế này.

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

Tôi nghĩ rằng mô hình khách truy cập thực sự là một cách phổ biến để thực hiện nhiều công văn. Xem ví dụ http://en.wikipedia.org/wiki/Double_dispatch#Double_dispatch_in_C.2B.2B Ví dụ nha sĩ của bạn có thể hơi khó hiểu vì chỉ có một nha sĩ, do đó bạn không thực sự cần công văn kép. :) – Sarien

+0

@Sarien điểm tốt, tôi đã thêm một bác sĩ vào ví dụ. Có khách truy cập là một cách rất phổ biến để thực hiện công văn kép. –

Các vấn đề liên quan