Mẫu thiết kế Adapter

Structural Design Pattern

Mục đích

  • Chuyển đổi giao diện của một hay nhiều lớp có sẵn thành một giao diện khác mà client mong muốn.  Adapter cho phép các lớp có các giao diện khác nhau có thể dể dàng giao tiếp tốt với nhau thông qua giao diện chuyển tiếp trung gian mà không cần thay đổi code của lớp có sẵn cũng như lớp đang viết.
  • Cung cấp một giao diện “bọc ngoài” tương thích cho một hệ thống có sẵn
  • Đối ứng phù hợp với các component cũ cho hệ thống mới

Vấn đề

Một component “có sẵn” với các tính năng đầy đủ có sẵn mà bạn muốn sử dụng lại, nhưng theo quan điểm mới nó lại không phù hợp với triết lý và kiến trúc của hệ thống đang được phát triển.

Thảo luận

 Vấn đề sử dụng lại luôn khó khăn và mất nhiều công sức. Lý do ở đây là sự rắc rối khi thiết kế một cái gì đó mới trong khi hoàn toàn có thể sử dụng lại cái cũ. Luôn luôn có một thứ gì đó không toàn đúng giữa cũ và mới. Nó có thể là kích thước vật lý hoặc sai lệch, có thể là thời gian hoặc sự đồng bộ hóa. Cũng có thể là giả định không may hoặc tiêu chuẩn cạnh tranh. Nó giống như vấn đề lắp một cái phích cắm ba chấu loại mới vào ổ cắm tường 2 chấu cũ, do đó một số công cụ chuyển đổi hoặc trung gian là cần thiết.

Adapter là việc tạo ra sự chuyển đổi trừu tượng trung gian, hoặc biểu đồ, hoặc đưa componennt cũ vào hệ thống mới. Client gọi phương thức của đối tượng Adapter, Adapter chuyển hướng lời gọi tới các hệ thống cũ. Chiến lược này có thể thực thi thông qua cơ chế kế thừa (inheritance) hoặc kết tập (aggregation).

Adapter hoạt động giống như một bộ bao gói (wrapper) hoặc bộ điều chỉnh (modifier) của lớp hiện tại. Nó cung cấp một cái nhìn khác về dịch vụ đó.

 Cấu trúc

Bên dưới, Thành phần LegacyRectangle với phương thức display() có các tham số đầu vào “x, y, w, h”. Nhưng Client muốn truyền vào “x1, y1, x2,  y2”. Sự khác biệt này có thể được dàn xếp bằng cách tạo một đối tượng bổ sung-ví dụ: Đối tượng Adapter.

Adapter cũng có thể được coi là một “wrapper”.

Ví dụ

Adapter pattern cho phép các lớp không tương thích làm việc cùng nhau bằng cách chuyển đổi giao diện của một lớp thành một giao diện mà các client mong đợi. Cái cờ lê là một ví dụ về Adapter. Ví dụ cần siết một con ốc, với điều kiện kích thước là như nhau. Kích thước chuẩn của Hoa Kỳ là 1/2 “và 1/4”. Rõ ràng, một con ốc cỡ 1/2 “sẽ không khớp với lỗ siết của cờ lê là 1/4” trừ khi sử dụng bộ chuyển đổi. Bộ chuyển đổi từ 1/2 “đến 1/4” có một đầu nối 1/2 “để lắp vào con ốc 1/2” và một đầu nối 1/4 “để khớp với lỗ siết của cờ lê 1/4”.

Danh sách kiểm tra

  1. Nhận diện người dùng: Các thành phần muốn làm cho phù hợp(ví dụ: client), và các thành phần cần chuyển đổi.
  2. Xác định giao diện mà client yêu cầu.
  3. Thiết kế class “wrapper” có thể đối ứng phù hợp adaptee cho client.
  4. Class adapter/wrapper “có một” thể hiện của lớp adaptee.
  5. Class adapter/wrapper “ánh xạ” giao diện client đến giao diện adaptee.
  6. Client sử dụng(được kết hợp với) giao diện mới.

Qui tắc ngón tay cái:

  • Adapter làm cho mọi thứ hoạt động sau khi chúng được thiết kế; Làm cầu nối.
  • Bridge có cấu trúc tương tự, nhưng mục tiêu khác (tách một giao diện khỏi phần cài đặt). Adapter được trang bị để làm cho các lớp không liên quan làm việc cùng nhau.
  • Adapter cung cấp giao diện khác nhau cho đối ứng của nó. Proxy Định nghĩa một giao diện đại diện cho các đối tượng khác mà không làm thay đổi giao diện của các đối tượng được đại diện, điều này thực hiện được nhờ các Adapter., một Adapter sẽ phối hợp hai đối tượng khác nhau. Decorator giao diện nâng cao.
  • Adapter có nghĩa là thay đổi giao diện của một đối tượng hiện có. Decorator bổ sung thêm chức năng nhưng không làm thay đổi giao diện, trong mẫu thiết kế Decorator
  • Facade định nghĩa một giao diện mới, trong khi Adapter sử dụng lại giao diện cũ. Hãy nhớ rằng Adapter làm cho hai giao diện hiện tại hoạt động cùng nhau trái ngược với việc định nghĩa một giao diện hoàn toàn mới.

Ví dụ của việc làm thế nào để thực hiện mô hình Adapter trong Java

1) Trước

Bởi vì interface giữa 2 đối tượng Line và Rectangle là không tương thích nên user phải khôi phục lại loại của shape và tự cung cấp các  tham số chính xác.

class Line {
public void draw(int x1, int y1, int x2, int y2) {
System.out.println("Line from point A(" + x1 + ";" + y1 + "), to point B(" + x2 + ";" + y2 + ")");
}
}

class Rectangle {
public void draw(int x, int y, int width, int height) {
System.out.println("Rectangle with coordinate left-down point (" + x + ";" + y + "), width: " + width
+ ", height: " + height);
}
}

public class AdapterDemo {
public static void main(String[] args) {
Object[] shapes = {new Line(), new Rectangle()};
int x1 = 10, y1 = 20;
int x2 = 30, y2 = 60;
int width = 40, height = 40;
for (Object shape : shapes) {
if (shape.getClass().getSimpleName().equals("Line")) {
((Line)shape).draw(x1, y1, x2, y2);
} else if (shape.getClass().getSimpleName().equals("Rectangle")) {
((Rectangle)shape).draw(x2, y2, width, height);
}
}
}
}

 Kết quả

Line from point A(10;20), to point B(30;60)
Rectangle with coordinate left-down point (30;60), width: 40, height: 40

2) Sau

Tạo ra một interface common Shape từ đó các class Adapter có thể thực thi và ghi đè lại phương thức draw theo mục đích riêng của mình.

interface Shape {
void draw(int x, int y, int z, int j);
}

class Line {
public void draw(int x1, int y1, int x2, int y2) {
System.out.println("Line from point A(" + x1 + ";" + y1 + "), to point B(" + x2 + ";" + y2 + ")");
}
}

class Rectangle {
public void draw(int x, int y, int width, int height) {
System.out.println("Rectangle with coordinate left-down point (" + x + ";" + y + "), width: " + width
+ ", height: " + height);
}
}

class LineAdapter implements Shape {
private Line adaptee;

public LineAdapter(Line line) {
this.adaptee = line;
}

@Override
public void draw(int x1, int y1, int x2, int y2) {
adaptee.draw(x1, y1, x2, y2);
}
}

class RectangleAdapter implements Shape {
private Rectangle adaptee;

public RectangleAdapter(Rectangle rectangle) {
this.adaptee = rectangle;
}

@Override
public void draw(int x1, int y1, int x2, int y2) {
int x = Math.min(x1, x2);
int y = Math.min(y1, y2);
int width = Math.abs(x2 - x1);
int height = Math.abs(y2 - y1);
adaptee.draw(x, y, width, height);
}
}

public class AdapterDemo {
public static void main(String[] args) {
Shape[] shapes = {new RectangleAdapter(new Rectangle()),
new LineAdapter(new Line())};
int x1 = 10, y1 = 20;
int x2 = 30, y2 = 60;
for (Shape shape : shapes) {
shape.draw(x1, y1, x2, y2);
}
}
}

Kết quả

Rectangle with coordinate left-down point (10;20), width: 20, height: 40
Line from point A(10;20), to point B(30;60)


Hãy tham gia nhóm Học lập trình để thảo luận thêm về các vấn đề cùng quan tâm.

Leave a Reply

Your email address will not be published. Required fields are marked *