28

Tôi đang cố gắng thiết kế một khung công tác không đồng bộ và muốn biết mọi người nghĩ gì về ưu điểm/nhược điểm của mẫu gọi lại so với mẫu quan sát viên.Gọi lại/Command vs EventListener/Observer Pattern

Callback pattern: 

//example callback 
public interface Callback{ 
    public void notify(MethodResult result); 
} 

//example method 
public class Worker{ 
    public void doAsyncWork(Callback callback){ 
    //do work 
    callback.notify(result); 
    } 
} 

//example observer pattern 
public interface EventListener{ 
    public void notify(MethodResult result); 

} 

public class Worker{ 
    private EventListener listener; 
    public registerEventListener(EventListener listener){ 
    this.listener=listener; 
    } 
    public void doAsyncWork(){ 
    //do work 
    listener.notify(result); 
    } 
} 

Tôi đang làm việc với một khuôn khổ có vẻ như sử dụng cả hai mẫu này. Mẫu EventListener không phải là mẫu điển hình vì nó không có danh sách người nghe. Điều này có thể dễ dàng được triển khai mặc dù bằng cách tạo một CompositeListener có ngữ nghĩa riêng về mức độ ưu tiên của người nghe và cách xử lý sự phân bố các sự kiện cho mỗi người nghe, ví dụ: sinh ra một chuỗi mới cho mỗi người nghe và thông báo nối tiếp. (Tôi thực sự nghĩ rằng đây là một ý tưởng tốt vì nó là một sự tách biệt tốt các mối quan tâm và là một sự cải tiến trên mẫu quan sát/người nghe chuẩn).

Bất kỳ suy nghĩ nào về thời điểm bạn nên sử dụng?

Thxs.

+0

Để đơn giản hóa việc gọi lại tôi khuyên bạn nên sử dụng chức năng hạng nhất. vì vậy nó chỉ 'public void doAsyncWork (Chức năng gọi lại) ' – Raynos

+0

Tôi mới cho cả các mẫu thiết kế, và tôi đã rất bối rối với mẫu mã của bạn. Bạn có chắc đây là bản demo chính xác của hai mẫu này, đặc biệt là mẫu Observer? Với tôi, cách bạn viết chúng không có gì khác biệt. Đừng hiểu lầm tôi. Tôi chân thành đánh giá cao câu hỏi của bạn vì tôi có cùng một điều trong tâm trí. Chỉ muốn thẳng ra. Cảm ơn! – jiu9x9uij

Trả lời

22

Cả hai mô hình là rất lớn và cái nào để chọn phụ thuộc vào những gì bạn đang đi để xây dựng và làm thế nào khuôn khổ của bạn sẽ được sử dụng.

Nếu bạn đang cố gắng để xây dựng một số loại publish-đăng ký hệ thống với dòng chảy điển hình sau đây của tác phẩm:

  • khách hàng bắt đầu nhiệm vụ async và quên về nó
  • nhiều bộ xử lý nhận được thông báo khi công việc được hoàn thành

thì Observer mẫu là lựa chọn tự nhiên cho bạn. Khi bạn đang thực hiện một khung công tác, bạn cũng nên xem xét sử dụng mẫu EventBus để đạt được khớp nối lỏng lẻo.

Nếu bạn cần gì hơn là một thực hiện không đồng bộ đơn giản và một dòng chảy điển hình sử dụng các khuôn khổ của bạn là:

  • nhiệm vụ bắt đầu async
  • làm điều gì đó khi nó được hoàn thành

hoặc

  • bắt đầu nhiệm vụ không đồng bộ
  • làm điều gì đó
  • chờ đợi cho đến khi nó được hoàn thành và làm điều gì đó

thì bạn nên đi với đơn giản Callback.

Nhưng để đạt được API dễ sử dụng hơn và sạch hơn, tôi khuyên bạn nên loại bỏ Callback trừu tượng và thiết kế mã công nhân của bạn để trả về một loại Future.

public interface Worker<T> { 

    Future<T> doAsync(); 

} 

Worker thể được sử dụng sau cách:

Future<Integer> future = worker.doAsync(); 

// some work here 

Integer result = future.get(); // waits till async work is done 

Future có thể là một tiêu chuẩn java Future. Nhưng tôi khuyên bạn nên sử dụng ListenableFuture từ thư viện ổi.

5

Tôi cho rằng mẫu gọi lại tốt hơn vì nó đơn giản hơn, có nghĩa là sẽ dễ dự đoán hơn và ít có khả năng bị lỗi do trạng thái đột biến của chính nó. Một ví dụ về điều này trong hoạt động sẽ là the way GWT handles browser/server communication.

Bạn có thể muốn sử dụng Generics mặc dù:

//example callback 
public interface Callback<T> { 
    public void notify(T result); 
} 

//example method 
public class Worker{ 
    public void doAsyncWork(Callback<SomeTypeOrOther> callback){ 
    //do work 
    callback.notify(result); 
    } 
} 
25

Command, gọi lại và quan sát mẫu có ngữ nghĩa khác nhau:

  • callback - thông báo cho một người gọi duy nhất một số hoạt động kết thúc với kết quả một số
  • quan sát - thông báo số không đến bên n quan tâm rằng một số sự kiện (ví dụ như một hoạt động đã hoàn thành) đã xảy ra
  • lệnh - gói gọn một cuộc gọi hoạt động trong một đối tượng do đó làm cho nó có thể chuyển nhượng qua một dây hoặc kéo dài-thể

Trong ví dụ của bạn, bạn có thể kết hợp cả hai mô hình gọi lại và quan sát để đạt API linh hoạt hơn:

  1. Sử dụng mô hình callback để kích hoạt hoạt động và thông báo cho người gọi không đồng bộ mà hoạt động đã kích hoạt đã hoàn tất.
  2. Sử dụng sự kiện/quan sát mẫu để cung cấp cho một số thành phần khác (mà đã không kích hoạt các hoạt động) có cơ hội để được thông báo khi phẫu thuật xong.
+1

Điểm mấu chốt ở đây là: - sử dụng gọi lại để thông báo cho triggerer - sử dụng các sự kiện cháy để thông báo cho các quan sát viên, mà trong trường hợp này, sẽ không có kích hoạt sự kiện này. – metakungfu

+1

Lời giải thích về sự khác nhau giữa ba mẫu là hữu ích cho tôi. – Sentimental