Mục đích
Mediator Pattern là một mẫu thiết kế hành vi giúp giảm thiểu sự phụ thuộc lẫn nhau và sự hỗn loạn giữa các đối tượng. Mẫu này giới hạn sự giao tiếp trực tiếp giữa các đối tượng và buộc chúng phải hợp tác thông qua một đối tượng trung gian.
Ứng dụng
- Mediator Pattern được sử dụng khi các đối tượng và các đối tượng khác liên kết chặt chẽ đến mức khó có thể thay đổi.
- Khi các thành phần không thể được tái sử dụng trong các ứng dụng khác vì sự phụ thuộc quá mức vào các thành phần khác.
- Khi bạn cần tạo ra một số hành vi cơ bản có thể được tái sử dụng trong các tình huống khác nhau, nhưng điều này dẫn đến việc phải tạo ra nhiều lớp con của thành phần.
Cấu trúc
Giải thích cấu trúc
- Component (Thành phần) là các lớp chứa logic kinh doanh. Mỗi thành phần có một tham chiếu đến trung gian, được khai báo dưới dạng kiểu giao diện trung gian. Thành phần không biết lớp trung gian thực tế, do đó bạn có thể tái sử dụng nó trong các chương trình khác nhau bằng cách kết nối nó với các trung gian khác nhau.
- Mediator (Trung gian) là giao diện khai báo các phương thức để giao tiếp với thành phần, nhưng thường chỉ bao gồm một phương thức thông báo. Thành phần có thể chuyển bất kỳ ngữ cảnh nào (bao gồm đối tượng của chính nó) làm đối số cho phương thức này, chỉ khi đó thành phần và lớp gửi không bị ràng buộc chặt chẽ.
- Concrete Mediator (Trung gian cụ thể) đóng gói các mối quan hệ giữa nhiều thành phần. Trung gian cụ thể thường lưu trữ tham chiếu đến tất cả các thành phần và quản lý chúng, thậm chí có thể quản lý vòng đời của chúng.
- Thành phần không biết về tình hình của các thành phần khác. Nếu có sự kiện quan trọng xảy ra trong thành phần, nó chỉ có thể thông báo cho trung gian. Sau khi nhận được thông báo, trung gian có thể dễ dàng xác định người gửi, điều này có thể đủ để xác định thành phần tiếp theo cần kích hoạt.
Mẫu code cấu trúc
Mediator: Định nghĩa một giao diện giao tiếp cho các đối tượng Colleague.
ConcreteMediator: Thực hiện giao diện giao tiếp trong Mediator. Lớp này cần hiểu và duy trì tất cả các đối tượng Colleague.
Nhóm Colleague: Mỗi đối tượng Colleague nên biết về đối tượng Mediator của nó, nhưng không biết về các đối tượng Colleague khác. Nó chỉ có thể liên lạc với đối tượng Mediator.
Khách hàng
Đầu ra
Đồng nghiệp 2 nhận được thông điệp: Bạn khỏe không?
Đồng nghiệp 1 nhận được thông điệp: Tốt, cảm ơn bạn. Còn bạn?
Đồng nghiệp 2 nhận được thông điệp: Mình cũng tốt, cảm ơn.
Pseudocode
Trong ví dụ này, Mediator Pattern giúp giảm thiểu sự phụ thuộc lẫn nhau giữa các lớp giao diện người dùng (Button, Checkbox và Textbox).
Các phần tử được kích hoạt bởi người dùng không giao tiếp trực tiếp với các phần tử khác, mặc dù có vẻ như chúng nên làm như vậy. Thay vào đó, các phần tử chỉ cần thông báo cho trung gian về sự kiện và có thể truyền bất kỳ thông tin ngữ cảnh nào cùng với thông báo.
Trong ví dụ này, trung gian là hộp thoại xác thực. Hộp thoại biết cách các phần tử cụ thể phối hợp và tạo điều kiện cho giao tiếp gián tiếp giữa chúng. Khi nhận được thông báo sự kiện, hộp thoại xác thực xác định phần tử chịu trách nhiệm xử lý sự kiện và chuyển tiếp yêu cầu dựa trên điều đó.
Mối quan hệ với các mẫu khác
- Chain of Responsibility Pattern, Command Pattern, Mediator Pattern và Observer Pattern được sử dụng để xử lý các kết nối khác nhau giữa người gửi yêu cầu và người nhận:
- Chain of Responsibility Pattern chuyển động động cơ yêu cầu cho một loạt các người nhận tiềm năng cho đến khi một trong số chúng xử lý yêu cầu.
- Command Pattern thiết lập một kết nối một chiều giữa người gửi và người nhận yêu cầu.
- Mediator Pattern loại bỏ kết nối trực tiếp giữa người gửi và người nhận, buộc chúng phải giao tiếp gián tiếp thông qua một đối tượng trung gian.
- Observer Pattern cho phép người nhận đăng ký hoặc hủy đăng ký động để nhận yêu cầu.
- Facade Pattern và Mediator Pattern có trách nhiệm tương tự nhau: cả hai đều cố gắng tổ chức sự hợp tác trong một số lượng lớn các lớp chặt chẽ kết nối.
- Facade định nghĩa một giao diện đơn giản cho tất cả các đối tượng trong hệ thống con, nhưng nó không cung cấp bất kỳ chức năng mới nào. Các đối tượng trong hệ thống con không nhận thức về sự tồn tại của fasade và có thể giao tiếp trực tiếp với nhau.
- Mediator tập trung trung tâm hóa hành vi giao tiếp của các thành phần trong hệ thống. Các thành phần khác chỉ biết về đối tượng trung gian và không thể giao tiếp trực tiếp với nhau.
- Việc phân biệt giữa Mediator Pattern và Observer Pattern thường khá khó nhớ. Trong hầu hết các trường hợp, bạn có thể sử dụng một trong hai mẫu, và đôi khi bạn có thể sử dụng cả hai cùng một lúc. Hãy xem cách làm điều này.
- Mục tiêu chính của Mediator là loại bỏ sự phụ thuộc chặt chẽ giữa các thành phần của hệ thống. Các thành phần này sẽ phụ thuộc vào cùng một đối tượng trung gian. Mục tiêu của Observer là thiết lập các kết nối động giữa các đối tượng, trong đó một số đối tượng có thể phụ thuộc vào các đối tượng khác.
- Có một cách triển khai phổ biến của mẫu trung gian dựa trên Observer. Đối tượng trung gian đóng vai trò nhà xuất bản, trong khi các thành phần khác đóng vai trò là người đăng ký và có thể đăng ký hoặc hủy đăng ký đối tượng trung gian. Khi Mediator được triển khai theo cách này, nó có thể trông giống như Observer rất nhiều.
- Khi bạn cảm thấy bối rối, hãy nhớ rằng có thể triển khai Mediator theo cách khác. Ví dụ, bạn có thể liên kết tất cả các thành phần với cùng một đối tượng trung gian vĩnh viễn. Cách triển khai này không giống với Observer, nhưng nó vẫn là một cách triển khai của mẫu trung gian.
- Giả sử có một chương trình trong đó tất cả các thành phần trở thành nhà xuất bản và chúng có thể thiết lập kết nối động với nhau. Trong trường hợp này, không có đối tượng trung tâm trung gian, mà chỉ có các nhà xuất bản phân tán.
Ví dụ
Ứng dụng: Mẫu trung gian thường được sử dụng trong mã Java để hỗ trợ giao tiếp giữa các thành phần giao diện người dùng của chương trình. Trong mô hình MVC, bộ điều khiển (controller) được coi là một trung gian.
Dưới đây là một số ví dụ về việc sử dụng mẫu này trong thư viện Java cốt lõi:
java.util.Timer
(tất cả các phương thứcscheduleXXX()
)java.util.concurrent.Executor#execute()
java.util.concurrent.ExecutorService
(các phương thứcinvokeXXX()
vàsubmit()
)java.util.concurrent.ScheduledExecutorService
(tất cả các phương thứcscheduleXXX()
)java.lang.reflect.Method#invoke()