Mục đích
- Cung cấp một giao diện
nhất quán cho tập hợp các giao diện trong một subsystem. Facade Pattern định
nghĩa một giao diện ở một cấp độ cao hơn để giúp cho người dùng có thể dễ dàng
sử dụng subsystem này vì chỉ cần giao tiếp với một giao diện chung duy nhất.
- Bao bọc một subsystem phức
tạp với một giao diện đơn giản.
Vấn đề
Một phân đoạn của client
community cần một giao diện đơn giản cho toàn thể các chức năng của một
subsystem phức tạp.
Thảo luận
Facade che đi sự phức tạp
của các thành phần subsystem (phụ) đối với client. Khắc phục cấu trúc khớp
nối lỏng lẻo giữa các subsystem với nhau và giữa các subsystem với client. Mặt
khác, nếu Facade chỉ là điểm truy cập duy nhất cho subsystem nó sẽ giới hạn
tính năng và tính linh hoạt mà “những người sử dụng thành thạo” có thể cần. Đối
tượng Facade nên điều phối hoặc hỗ trợ đơn giản. Nó không nên trở thành một nhà
tiên tri biết tất cả mọi thứ hay một đối tương “thần thánh” nào đó.
Cấu trúc
Facade sẽ lấy một
"thứ khó hiểu bí ẩn được phủ trong sự thần bí" và chen vào một lớp phủ
để có thể thuần hóa sự vô định hình và tính khó hiểu của đống phần mềm hỗn độn
đó.
SubsystemOne và
SubsystemThree không tương tác trực tiếp với các thành phận nội tại của
SubsystemTwo thay vào đó chúng sử dụng SussystemTwoWrapper “facade”(ví dụ: Trừu
tượng ở cấp độ cao”)
Ví dụ
Facade định nghĩa một giao diện thống nhất,
cấp cao hơn cho một subsystem làm cho nó sử dụng dễ dàng hơn. Người mua gặp
Facade khi đặt hàng từ một cửa hàng. Người mua gọi vào một số và nói chuyện với
đại diện dịch vụ khách hàng. Bộ phận đại diện dịch vụ khách hàng đóng vai trò như Facade,
cung cấp giao diện cho bộ phận hoàn thành đơn đặt hàng, bộ phận thanh toán và bộ
phận vận chuyển.
Danh sách kiểm tra
- Nhận diện một giao diện
đơn giản, thống nhất cho cho subsystem hoặc component.
- Thiết kế class “bọc
ngoài” đóng gói subsystem.
- Facade(hay còn gọi là
wrapper) nắm bắt sự phức tạp và cộng tác của các component và phân công xử lý
cho các method thích hợp.
- Client sử dụng (Chỉ giao
tiếp) với Facade.
- Cân nhắc việc thêm hay
không thêm Facade khi muốn tạo dữ liệu.
Quy tắc chung
- Facade định nghĩa một
interface mới, trong khi Adapter sử dụng interface cũ. Hãy nhớ rằng Adapter làm
cho hai interface hiện tại có thể làm việc cùng nhau trái ngược với việc tạo một
interface hoàn toàn mới.
- Trong khi Flyweight cho
thấy làm thế nào để làm việc trên nhiều đối tượng thì Facade cho thấy làm thế
nào để một đối tượng đại diện cho toàn bộ subsystem.
- Mediator tương tự như
Facade trong đó nó trừu tượng hóa chức năng của các lớp hiện tại. Mediator trừu
tượng hóa/tập trung tùy ý sự giao tiếp giữa các đối tượng tương đồng.Nó thường
“adds value” và nó được biết/tham chiếu bởi các đối tượng tương đồng. Ngược lại,
Facade định nghĩa một giao diện đơn giản, nó không thêm mới chức năng. và nó
cũng không được biết đến bởi các lớp subsystem.
- Abstract Factory có thể
được sử dụng như một thay thế cho Facade cho việc ẩn các lớp nền tảng được chỉ
định.
- Đối tượng Facade thường
là Singletons vì chỉ có một đối tượng Facade là cần thiết.
- Adapter và Facade cả hai
đều là bọc ngoài(wrappers) nhưng chúng là các loại wrapper khác nhau. Mục đích
của Facade là tạo ra một interface đơn giản còn mục đích của Adapter là thiết kế
trên interface hiện có. Trong khi Facade thường kết hợp nhiều đối tượng thì
Adapter chỉ kết hợp một đối tượng duy nhất; Facade có thể front-end một đối tượng
phức tạp đơn lẻ và Adapter có thể gói một vài đối tượng kế thừa.
Câu hỏi: Sự khác nhau giữa Adapter pattern và Facade pattern là
Adapter bao bọc một lớp còn Facade có thể đại diện cho nhiều lớp đúng hay
không?
Trả lời: Không! Hãy nhớ rằng, Adapter pattern thay đổi giao diện
của một hoặc nhiều lớp thành một giao diện mà client mong muốn. Trong khi các
ví dụ trong sách phổ biến chỉ ra rằng adapter adapting cho một lớp, bạn cần phải
adapt nhiều lớp để cung cấp giao diện cho một client đã được xây dựng. Tương tự
như vậy, Facade cung cấp một giao diện đơn giản cho một lớp duy nhất với 1 giao
diện phức tạp. Sự khác nhau giữa 2 loại trên không phải là về số lượng các lớp
chúng “wrap” mà là về mục đích của chúng.
Ví dụ về làm thế nào để
thực thi một mẫu thiết kế Facade trong Java
Mẫu thiết kế
Facade
- Xác định một interface
mong muốn cho tập hợp subsystems
- Thiết kế “wrapper” class
có thể đóng gói sử dụng của các subsystems
- Client sử dụng(kết hợp với)
Facade
- Facade/wrapper
“ánh xa” vào các API của các subsystems
// 1. Subsystemclass PointCartesian {
private double x, y;
public PointCartesian(double x, double y ) {
this.x = x;
this.y = y;
}
public void move( int x, int y ) {
this.x += x;
this.y += y;
}
public String toString() {
return "(" + x + "," + y + ")";
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}
// 1. Subsystemclass PointPolar {
private double radius, angle;
public PointPolar(double radius, double angle) {
this.radius = radius;
this.angle = angle;
}
public void rotate(int angle) {
this.angle += angle % 360;
}
public String toString() {
return "[" + radius + "@" + angle + "]";
}
}
// 1. Desired interface: move(), rotate()class Point {
// 2. Design a "wrapper" class private PointCartesian pointCartesian;
public Point(double x, double y) {
pointCartesian = new PointCartesian(x, y);
}
public String toString() {
return pointCartesian.toString();
}
// 4. Wrapper maps public void move(int x, int y) {
pointCartesian.move(x, y);
}
public void rotate(int angle, Point o) {
double x = pointCartesian.getX() - o.pointCartesian.getX();
double y = pointCartesian.getY() - o.pointCartesian.getY();
PointPolar pointPolar = new PointPolar(Math.sqrt(x * x + y * y),Math.atan2(y, x) * 180 / Math.PI);
// 4. Wrapper maps pointPolar.rotate(angle);
System.out.println(" PointPolar is " + pointPolar);
String str = pointPolar.toString();
int i = str.indexOf('@');
double r = Double.parseDouble(str.substring(1, i));
double a = Double.parseDouble(str.substring(i + 1, str.length() - 1));
pointCartesian = new PointCartesian(r*Math.cos(a*Math.PI/180) + o.pointCartesian.getX(),
r*Math.sin(a * Math.PI / 180) + o.pointCartesian.getY());
}
}
class Line {
private Point o, e;
public Line(Point ori, Point end) {
o = ori;
e = end;
}
public void move(int x, int y) {
o.move(x, y);
e.move(x, y);
}
public void rotate(int angle) {
e.rotate(angle, o);
}
public String toString() {
return "origin is " + o + ", end is " + e;
}
}
public class FacadeDemo {
public static void main(String[] args) {
// 3. Client uses the Facade Line lineA = new Line(new Point(2, 4), new Point(5, 7));
lineA.move(-2, -4);
System.out.println( "after move: " + lineA );
lineA.rotate(45);
System.out.println( "after rotate: " + lineA );
Line lineB = new Line( new Point(2, 1), new Point(2.866, 1.5));
lineB.rotate(30);
System.out.println("30 degrees to 60 degrees: " + lineB);
}
}
Kết quả
after move: origin is (0.0,0.0), end is (3.0,3.0)
PointPolar is [4.242640687119285@90.0]
after rotate: origin is (0.0,0.0), end is (2.5978681687064796E-16,4.242640687119285)
PointPolar is [0.9999779997579947@60.000727780827376]
30 degrees to 60 degrees: origin is (2.0,1.0), end is (2.499977999677324,1.8660127018922195)
Đăng nhận xét