Trong khi viết mã OOP, tôi áp dụng một số thực hành của Elegant Objects.
Một trong số đó là các lớp học phải là lớp cuối cùng. Điều này có nghĩa là chúng không thể được mở rộng thông qua kế thừa mà chỉ thông qua thành phần.
Ưu điểm là sự đơn giản. Ý tôi là, theo cách này, mỗi đối tượng được xem như một khối gắn kết. Điều quan tâm đối với khách hàng của nó là hành vi tiếp xúc của nó. Chỉ có bấy nhiêu thôi. Thay vào đó, thông qua tiện ích mở rộng, khách hàng có thể phá vỡ nó.
Ví dụ, một đối tượng có thể xen kẽ hai phương thức của nó. Vì vậy, nếu chúng ta có thể thay thế thông qua phần mở rộng một trong số chúng, chúng ta có thể phá vỡ phần còn lại. Vì lý do này, để chắc chắn, chúng ta nên kiểm tra việc thực hiện nó. Bằng cách này, chúng tôi tăng khả năng ghép nối giữa phần mở rộng và phần mở rộng.
Nói cách khác, các lớp cuối cùng thực thi ý tưởng rằng chúng ta chỉ nên quan tâm đến hành vi tiếp xúc. Và không thực hiện. Tuy nhiên, nó đòi hỏi một sự thay đổi về cách chúng ta lập luận về chúng. Mẫu Bí danh đơn giản hóa một khía cạnh của thay đổi này.
Mẫu bí danh cho phép mở rộng cách một lớp có thể xây dựng các đối tượng của nó mà không cần phân lớp hoặc sửa đổi nó.
Giả sử một lớp cuối cùng tạo ra các đối tượng của nó bằng cách sử dụng một số tham số bắt buộc. Làm thế nào chúng ta có thể thêm một cách khác để tạo các đối tượng của nó? Ví dụ, làm thế nào chúng ta có thể thêm một hàm tạo sử dụng giá trị mặc định cho một hoặc nhiều tham số bị thiếu của nó?
Một cách tiếp cận có thể là thêm một hàm tạo khác vào lớp. Nhưng điều này có thể vượt khỏi tầm tay. Hơn nữa, nó không thể được. Ví dụ, lớp cuối cùng nói trên có thể nằm trong một thư viện bên ngoài.
Một nhược điểm khác của phương pháp này là chúng ta có thể gây ô nhiễm cho lớp cuối cùng. Ví dụ, chúng ta có thể có một lớp cuối cùng xây dựng các đối tượng của nó với một JSON. Nhưng sau một thời gian, chúng ta cần thêm cả XML. Như bạn có thể tưởng tượng việc thêm mã để ánh xạ XML sang JSON chắc chắn sẽ gây ô nhiễm lớp đó.
Tuy nhiên, mẫu Bí danh không giới hạn ở các lớp cuối cùng. Ví dụ, chúng ta không thể có hai hàm tạo có cùng tham số nhưng ngữ nghĩa khác nhau.
Để giải quyết vấn đề này, chúng ta có thể thêm các phương thức nhà máy tĩnh vào mã lớp. Nhưng những nhược điểm nói trên cũng ảnh hưởng đến cách tiếp cận này. Đó là: điều này vượt khỏi tầm tay; điều này không phải lúc nào cũng có thể có được; điều này sẽ làm ô nhiễm lớp học.
Một cách tiếp cận tốt hơn cho cả hai vấn đề là tạo một lớp khác với hành vi của hàm tạo mong muốn. Lớp này đóng gói logic xây dựng của riêng nó. Và nó sẽ ủy thác mọi thứ cho lớp khác, bao gồm cả việc tạo thực tế. Đây là mẫu Bí danh.
Sử dụng mẫu Bí danh khi:
Bạn cần thêm hoặc sửa đổi hàm tạo của một lớp cuối cùng;
Bạn muốn thêm hoặc sửa đổi phương thức khởi tạo của một lớp mà không cần sửa đổi hoặc phân lớp nó;
Bạn cần hai hoặc nhiều phương thức khởi tạo của một lớp có cùng tham số mà không cần sửa đổi hoặc phân lớp nó.
Cấu trúc là đơn giản. Chúng ta cần ít nhất hai lớp triển khai cùng một giao diện: một Alias
và một Aliased.
AnInterface
khai báo một giao diện.
Aliased
triển khai AnInterface
;
để lộ một hoặc nhiều hàm tạo.
Alias
AnInterface
;Aliased
;Aliased
được tham chiếu.Alias
xây dựng - theo các quy tắc riêng của nó - một đối tượng Aliased
và duy trì một tham chiếu của nó. Sau đó, nó ủy quyền mọi thứ cho bí danh.
Mô hình Bí danh có các hậu quả sau:
Để triển khai mẫu Bí danh, bạn cần:
để xác định một giao diện;
để triển khai giao diện được xác định trước đó với một lớp. Đây sẽ là bí danh;
để triển khai giao diện đã xác định trước đó với một lớp bí danh và bạn cần:
Mã Java-ish dưới đây thể hiện mẫu Bí danh. Trong mã này, bí danh chèn một giá trị mặc định cho một tham số bắt buộc khác:
interface AnInterface { void aMethod(); Something anotherMethod(); } final class Aliased implements AnInterface { private final A a; private final B b; Aliased(final A a, final B b) { this.a = a; this.b = b; } void aMethod() { // implementation } Something anotherMethod() { // implementation } } final class Alias implements AnInterface { private final Aliased aliased; Alias(final A a) { this( new Aliased( a, new InstanceOfB(...) ) ); } private Alias(final Aliased aliased) { this.aliased = aliased; } void aMethod() { this.aliased.aMethod(); } Something anotherMethod() { return this.aliased.anotherMethod(); } }
Ở một mức độ nhất định, mô hình Bí danh cũng có thể được coi là một cách để trang trí cấu trúc vật thể. Tầm nhìn này đặc biệt đúng nếu chúng ta xem một lớp là một đối tượng có trách nhiệm tạo ra các đối tượng.