Mediator Pattern Là Gì?
Mediator là một mẫu thiết kế (design pattern) thuộc nhóm behavioral. Mục tiêu của Mediator pattern là giảm sự phụ thuộc giữa các đối tượng trong một hệ thống phức tạp bằng cách tạo ra một đối tượng trung gian (mediator) để chứa logic giao tiếp giữa các đối tượng khác nhau.
Trong Mediator pattern, các đối tượng không giao tiếp trực tiếp với nhau, mà thay vào đó, chúng giao tiếp thông qua đối tượng mediator. Điều này giúp giảm sự rắc rối và tăng tính linh hoạt của hệ thống, vì mỗi đối tượng chỉ cần biết về đối tượng mediator thay vì phải biết về tất cả các đối tượng khác trong hệ thống.
Tình Huống Bài Toán
Giả sử chúng ta có một phần mềm, trong đó các dịch vụ được giao tiếp với nhau thông qua nhiều đối tượng, dẫn đến việc họ phụ thuộc vào nhau quá mức.
Tại Sao Phải Dùng Mediator?
Phân tích tình huống, chúng ta có thể thấy rằng các đối tượng có những vấn đề sau:
- Phụ thuộc mạnh mẽ: Các đối tượng có thể trở nên kết nối chặt chẽ với nhau, dẫn tới sự phức tạp trong việc duy trì mã nguồn.
- Khả năng mở rộng giảm: Việc thêm chức năng hoặc thay đổi trong hệ thống có thể gây ra tác động phụ không mong muốn.
- Khả năng tái sử dụng giảm: Các đối tượng không được thiết kế để tái sử dụng dễ dàng trong các ngữ cảnh khác nhau.
Mô hình Mediator giúp giải quyết những vấn đề này bằng cách tạo ra một lớp trung gian để điều phối mọi tương tác giữa các đối tượng, giữ cho chúng độc lập và giảm thiểu sự phụ thuộc. Tuy nhiên, mọi giải pháp đều có những hạn chế. Chúng ta sẽ bàn luận về điều này sau.
Triển Khai Mediator Pattern Bằng C#
Chúng ta sẽ triển khai mô hình trên bằng ngôn ngữ lập trình C#. Để bắt đầu, cần tạo một dự án Console App trong Visual Studio và thực hiện các bước sau:
Bước 1: Tạo Interface IRequest
csharp
public interface IRequest<out TResponse>;
Interface này định nghĩa ràng buộc cho các lớp implement và sẽ trả về kiểu dữ liệu dạng TResponse.
Bước 2: Tạo Interface IRequestHandler<in TRequest, TResponse>
csharp
public interface IRequestHandler<in TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
Task<TResponse> Handle(TRequest request);
}
Interface này định nghĩa ràng buộc nhận vào kiểu TRequest và trả về TResponse. Phương thức Handle sẽ được sử dụng để xử lý yêu cầu.
Bước 3: Định Nghĩa Interface IMediator
csharp
public interface IMediator
{
Task<TResponse> Send<TResponse>(IRequest<TResponse> request);
}
Interface này chứa phương thức Send để gửi yêu cầu tới các lớp tương ứng.
Bước 4: Tạo Lớp Mediator Implement IMediator
csharp
public class Mediator(IServiceProvider serviceProvider) : IMediator
{
private readonly IServiceProvider _serviceProvider = serviceProvider;
public async Task<TResponse> Send<TResponse>(IRequest<TResponse> request)
{
ArgumentNullException.ThrowIfNull(request);
var requestType = request.GetType();
var wrapperType = typeof(RequestHandlerWrapper<,>).MakeGenericType(requestType, typeof(TResponse));
var wrapper = (RequestHandlerBase<TResponse>)Activator.CreateInstance(wrapperType);
return await wrapper.Handle(request, _serviceProvider);
}
}
Bước 5: Tạo Lớp RequestHandler Để Xử Lý Yêu Cầu
Ví dụ, để xử lý dữ liệu trả về từ Service A:
csharp
public class ServiceA : IRequest<string>
{
public class ServiceAHandler : IRequestHandler<ServiceA, string>
{
public async Task<string> Handle(ServiceA request)
{
return "Kết quả xử lý sau khi nhận giá trị yêu cầu ServiceARequest";
}
}
}
Các dịch vụ khác cũng sẽ implement tương tự để xử lý yêu cầu của riêng mình.
Bước 6: Đăng Ký Service Trong Program.cs
csharp
var services = new ServiceCollection();
services.AddScoped<IMediator, Mediator>();
services.AddScoped<IRequestHandler<ServiceA, string>, ServiceAHandler>();
...
var serviceProvider = services.BuildServiceProvider();
var mediator = serviceProvider.GetRequiredService<IMediator>();
var messageServiceA = await mediator.Send(new ServiceA());
Console.WriteLine(messageServiceA);
Nhược Điểm Của Mediator Pattern
Mặc dù Mediator Pattern có nhiều lợi ích, nhưng cũng tồn tại những nhược điểm:
- Tăng sự phức tạp: Khi số lượng đối tượng nhiều, mediator có thể trở nên phức tạp.
- Tính đóng gói thấp: Các đối tượng phải biết về mediator của chúng, làm giảm tính độc lập.
- Hiệu suất: Việc truyền thông qua mediator có thể tạo ra overhead không cần thiết.
- Khó hiểu và phức tạp: Các tương tác phức tạp có thể khó hiểu và debug.
Một Số Bài Toán Áp Dụng Mediator Pattern
- Triển khai ESB (Enterprise Service Bus).
- Tạo message brokers để trao đổi dữ liệu giữa các service hoặc worker.
- Triển khai CQRS pattern.
Kết Luận
Như vậy, chúng ta đã tìm hiểu cơ bản về Mediator Pattern và cách triển khai nó bằng ngôn ngữ lập trình C#. Hy vọng bài viết này sẽ hữu ích cho mọi người trong việc nâng cao kỹ năng thiết kế phần mềm. Nếu bạn thấy thông tin này hay, hãy đăng ký kênh của chúng tôi để nhận thêm nhiều kiến thức bổ ích nhé! Cảm ơn mọi người đã dành thời gian đọc bài viết này!
source: viblo