Bản thân các tác giả của Design Patterns cũng lo lắng nhất là mẫu "Khách".
Đó là một "điều xấu cần thiết" - nhưng thường được sử dụng quá mức và nhu cầu về nó thường bộc lộ một lỗ hổng cơ bản hơn trong thiết kế của bạn.
Tên thay thế cho mẫu "Khách truy cập" là "Nhiều cử", bởi vì mẫu Khách truy cập là thứ mà bạn kết thúc khi bạn muốn sử dụng ngôn ngữ OO của phái cử một loại để chọn mã để sử dụng dựa trên loại hai (hoặc nhiều hơn) các đối tượng khác nhau.
Ví dụ cổ điển là bạn có giao điểm giữa hai hình dạng, nhưng có một trường hợp đơn giản hơn thường bị bỏ qua: so sánh sự bằng nhau của hai đối tượng không đồng nhất.
Dù sao, bạn thường kết thúc với một cái gì đó như thế này:
interface IShape
{
double intersectWith(Triangle t);
double intersectWith(Rectangle r);
double intersectWith(Circle c);
}
Vấn đề với điều này là bạn đã kết hợp tất cả các triển khai "IShape" của mình lại với nhau. Bạn đã ngụ ý rằng bất cứ khi nào bạn muốn thêm một hình dạng mới vào hệ thống phân cấp, bạn cũng sẽ cần phải thay đổi tất cả các triển khai "Hình dạng" khác.
Đôi khi, đây là thiết kế tối giản chính xác - nhưng hãy suy nghĩ kỹ. Thiết kế của bạn có thực sự bắt buộc bạn phải gửi đến hai loại không? Bạn có sẵn sàng viết từng sự bùng nổ tổ hợp của nhiều phương pháp không?
Thông thường, bằng cách đưa ra một khái niệm khác, bạn có thể giảm số lượng kết hợp mà bạn thực sự sẽ phải viết:
interface IShape
{
Area getArea();
}
class Area
{
public double intersectWith(Area otherArea);
...
}
Tất nhiên, nó phụ thuộc - đôi khi bạn thực sự cần phải viết mã để xử lý tất cả các trường hợp khác nhau - nhưng bạn nên tạm dừng và suy nghĩ trước khi bắt tay vào sử dụng Visitor. Nó có thể giúp bạn đỡ đau đớn sau này.