![Mẫu thiết kế bộ điều hợp giải quyết vấn đề gì? - 1](https://cdn.codegym.cc/images/article/2a00c183-20f3-4a73-abc5-f1f896e18a52/800.jpeg)
Thêm về vấn đề
Đầu tiên, chúng tôi sẽ mô phỏng hành vi của hệ thống cũ. Giả sử nó viện cớ cho việc đi làm hoặc đi học muộn. Để làm điều này, nó có mộtExcuse
giao diện có generateExcuse()
và likeExcuse()
các dislikeExcuse()
phương thức.
public interface Excuse {
String generateExcuse();
void likeExcuse(String excuse);
void dislikeExcuse(String excuse);
}
Lớp WorkExcuse
thực hiện giao diện này:
public class WorkExcuse implements Excuse {
private String[] excuses = {"in an incredible confluence of circumstances, I ran out of hot water and had to wait until sunlight, focused using a magnifying glass, heated a mug of water so that I could wash.",
"the artificial intelligence in my alarm clock failed me, waking me up an hour earlier than normal. Because it is winter, I thought it was still nighttime and I fell back asleep. Everything after that is a bit hazy.",
"my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia."};
private String [] apologies = {"This will not happen again, of course. I'm very sorry.", "I apologize for my unprofessional behavior.", "There is no excuse for my actions. I am not worthy of this position."};
@Override
public String generateExcuse() { // Randomly select an excuse from the array
String result = "I was late today because " + excuses[(int) Math.round(Math.random() + 1)] + "\\n" +
apologies[(int) Math.round(Math.random() + 1)];
return result;
}
@Override
public void likeExcuse(String excuse) {
// Duplicate the element in the array so that its chances of being chosen are higher
}
@Override
public void dislikeExcuse(String excuse) {
// Remove the item from the array
}
}
Hãy kiểm tra ví dụ của chúng tôi:
Excuse excuse = new WorkExcuse();
System.out.println(excuse.generateExcuse());
Đầu ra:
"I was late today because my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia.
I apologize for my unprofessional behavior.
Bây giờ, hãy tưởng tượng rằng bạn đã khởi chạy một dịch vụ tạo lý do bào chữa, thu thập số liệu thống kê và nhận thấy rằng hầu hết người dùng của bạn là sinh viên đại học. Để phục vụ nhóm này tốt hơn, bạn đã yêu cầu một nhà phát triển khác tạo một hệ thống tạo ra các lý do cụ thể cho sinh viên đại học. Nhóm phát triển đã tiến hành nghiên cứu thị trường, xếp hạng các lý do bào chữa, kết nối một số trí tuệ nhân tạo và tích hợp dịch vụ với báo cáo giao thông, báo cáo thời tiết, v.v. Bây giờ bạn có một thư viện để tạo lý do cho sinh viên đại học, nhưng nó có giao diện khác: StudentExcuse
.
public interface StudentExcuse {
String generateExcuse();
void dislikeExcuse(String excuse);
}
Giao diện này có hai phương thức: generateExcuse
, tạo ra lý do và dislikeExcuse
, ngăn lý do xuất hiện lại trong tương lai. Thư viện của bên thứ ba không thể chỉnh sửa, tức là bạn không thể thay đổi mã nguồn của nó. Những gì chúng ta có bây giờ là một hệ thống có hai lớp triển khai Excuse
giao diện và một thư viện có một SuperStudentExcuse
lớp triển khai StudentExcuse
giao diện:
public class SuperStudentExcuse implements StudentExcuse {
@Override
public String generateExcuse() {
// Logic for the new functionality
return "An incredible excuse adapted to the current weather conditions, traffic jams, or delays in public transport schedules.";
}
@Override
public void dislikeExcuse(String excuse) {
// Adds the reason to a blacklist
}
}
Không thể thay đổi mã. Hệ thống phân cấp lớp hiện tại trông như thế này: ![Mẫu thiết kế bộ điều hợp giải quyết vấn đề gì? - 2](https://cdn.codegym.cc/images/article/5eb3ced7-e0e6-4dec-94a1-298d797d0e7d/800.jpeg)
![Mẫu thiết kế bộ điều hợp giải quyết vấn đề gì? - 3](https://cdn.codegym.cc/images/article/97a9295a-155b-4043-9c37-b187044a02df/800.jpeg)
Excuse
giao diện. Nhưng hệ thống phân cấp bổ sung là điều không mong muốn trong các ứng dụng nghiêm túc: việc đưa vào một phần tử gốc chung sẽ phá vỡ kiến trúc. Bạn nên triển khai một lớp trung gian cho phép chúng tôi sử dụng cả chức năng mới và cũ với tổn thất tối thiểu. Tóm lại, bạn cần một bộ chuyển đổi .
Nguyên tắc đằng sau mẫu bộ điều hợp
Bộ điều hợp là một đối tượng trung gian cho phép các lệnh gọi phương thức của một đối tượng này được hiểu bởi một đối tượng khác. Hãy triển khai một bộ điều hợp cho ví dụ của chúng ta và gọi nó làMiddleware
. Bộ điều hợp của chúng tôi phải triển khai giao diện tương thích với một trong các đối tượng. Hãy để nó được Excuse
. Điều này cho phép Middleware
gọi các phương thức của đối tượng đầu tiên. Middleware
nhận cuộc gọi và chuyển tiếp chúng theo cách tương thích tới đối tượng thứ hai. Đây là cách Middleware
triển khai với phương thức generateExcuse
và dislikeExcuse
:
public class Middleware implements Excuse { // 1. Middleware becomes compatible with WorkExcuse objects via the Excuse interface
private StudentExcuse superStudentExcuse;
public Middleware(StudentExcuse excuse) { // 2. Get a reference to the object being adapted
this.superStudentExcuse = excuse;
}
@Override
public String generateExcuse() {
return superStudentExcuse.generateExcuse(); // 3. The adapter implements an interface method
}
@Override
public void dislikeExcuse(String excuse) {
// The method first adds the excuse to the blacklist,
// Then passes it to the dislikeExcuse method of the superStudentExcuse object.
}
// The likeExcuse method will appear later
}
Kiểm tra (trong mã máy khách):
public class Test {
public static void main(String[] args) {
Excuse excuse = new WorkExcuse(); // We create objects of the classes
StudentExcuse newExcuse = new SuperStudentExcuse(); // that must be compatible.
System.out.println("An ordinary excuse for an employee:");
System.out.println(excuse.generateExcuse());
System.out.println("\n");
Excuse adaptedStudentExcuse = new Middleware(newExcuse); // Wrap the new functionality in the adapter object
System.out.println("Using new functionality with the adapter:");
System.out.println(adaptedStudentExcuse.generateExcuse()); // The adapter calls the adapted method
}
}
Đầu ra:
An ordinary excuse for an employee:
I was late today because my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia.
There is no excuse for my actions. I am not worthy of this position.
Using new functionality with the adapter:
Một lý do đáng kinh ngạc phù hợp với điều kiện thời tiết hiện tại, tắc đường hoặc chậm trễ trong lịch trình giao thông công cộng. Phương thức này generateExcuse
chỉ đơn giản chuyển lời gọi đến một đối tượng khác mà không có bất kỳ thay đổi bổ sung nào. Phương pháp này dislikeExcuse
yêu cầu chúng tôi đưa vào danh sách đen lý do đầu tiên. Khả năng thực hiện xử lý dữ liệu trung gian là lý do khiến mọi người yêu thích mẫu bộ điều hợp. Nhưng còn likeExcuse
phương thức, là một phần của Excuse
giao diện nhưng không phải là một phần của StudentExcuse
giao diện thì sao? Chức năng mới không hỗ trợ thao tác này. Các UnsupportedOperationException
đã được phát minh cho tình huống này. Nó bị ném nếu thao tác được yêu cầu không được hỗ trợ. Hãy sử dụng nó. Đây là cách Middleware
triển khai mới của lớp:
public class Middleware implements Excuse {
private StudentExcuse superStudentExcuse;
public Middleware(StudentExcuse excuse) {
this.superStudentExcuse = excuse;
}
@Override
public String generateExcuse() {
return superStudentExcuse.generateExcuse();
}
@Override
public void likeExcuse(String excuse) {
throw new UnsupportedOperationException("The likeExcuse method is not supported by the new functionality");
}
@Override
public void dislikeExcuse(String excuse) {
// The method accesses a database to fetch additional information,
// and then passes it to the superStudentExcuse object's dislikeExcuse method.
}
}
Thoạt nhìn, giải pháp này có vẻ không ổn lắm, nhưng việc bắt chước chức năng có thể làm phức tạp thêm tình hình. Nếu khách hàng chú ý và bộ điều hợp được ghi chép đầy đủ, thì giải pháp như vậy có thể chấp nhận được.
Khi nào nên sử dụng bộ chuyển đổi
-
Khi bạn cần sử dụng một lớp bên thứ ba, nhưng giao diện của nó không tương thích với ứng dụng chính. Ví dụ trên cho thấy cách tạo đối tượng bộ điều hợp kết thúc cuộc gọi theo định dạng mà đối tượng đích có thể hiểu được.
-
Khi một số lớp con hiện có cần một số chức năng chung. Thay vì tạo các lớp con bổ sung (sẽ dẫn đến trùng lặp mã), tốt hơn là sử dụng bộ điều hợp.
Ưu điểm và nhược điểm
Ưu điểm: Bộ điều hợp ẩn khỏi máy khách các chi tiết xử lý yêu cầu từ đối tượng này sang đối tượng khác. Mã máy khách không nghĩ đến việc định dạng dữ liệu hoặc xử lý các cuộc gọi đến phương thức đích. Nó quá phức tạp và các lập trình viên thì lười biếng :) Nhược điểm: Cơ sở mã của dự án phức tạp bởi các lớp bổ sung. Nếu bạn có nhiều giao diện không tương thích, số lượng các lớp bổ sung có thể trở nên không thể quản lý được.Đừng nhầm lẫn bộ điều hợp với mặt tiền hoặc trang trí
Chỉ với một cuộc kiểm tra bề ngoài, một bộ chuyển đổi có thể bị nhầm lẫn với các mẫu trang trí và mặt tiền. Sự khác biệt giữa bộ điều hợp và mặt tiền là mặt tiền giới thiệu một giao diện mới và bao bọc toàn bộ hệ thống con. Và một trình trang trí, không giống như một bộ điều hợp, thay đổi chính đối tượng chứ không phải giao diện.Thuật toán từng bước
-
Đầu tiên, hãy chắc chắn rằng bạn có một vấn đề mà mẫu này có thể giải quyết.
-
Xác định giao diện máy khách sẽ được sử dụng để tương tác gián tiếp với các đối tượng không tương thích.
-
Làm cho lớp bộ điều hợp kế thừa giao diện được xác định trong bước trước.
-
Trong lớp bộ điều hợp, hãy tạo một trường để lưu trữ tham chiếu đến đối tượng bộ điều hợp. Tham chiếu này được chuyển đến hàm tạo.
-
Triển khai tất cả các phương thức giao diện máy khách trong bộ điều hợp. Một phương pháp có thể:
-
Truyền cuộc gọi mà không thực hiện bất kỳ thay đổi nào
-
Sửa đổi, bổ sung dữ liệu, tăng/giảm số lần gọi phương thức đích, v.v.
-
Trong trường hợp cực đoan, nếu một phương thức cụ thể vẫn không tương thích, hãy đưa ra Ngoại lệ UnsupportedOperationException. Các hoạt động không được hỗ trợ phải được ghi lại nghiêm ngặt.
-
-
Nếu ứng dụng chỉ sử dụng lớp bộ điều hợp thông qua giao diện máy khách (như trong ví dụ trên), thì bộ điều hợp có thể được mở rộng dễ dàng trong tương lai.