Design Pattern Tiếng Việt Help

Bridge

Giới thiệu

Định nghĩa Pattern

Bridge Pattern là một mẫu thiết kế thuộc loại cấu trúc. Nó giúp tách rời abstraction (lớp trừu tượng) và implementation (lớp thực thi) ra khỏi nhau, giúp cả hai có thể thay đổi và phát triển một cách độc lập, không làm ảnh hưởng đến nhau.

Mục đích

  • Tách biệt abstraction khỏi implementation để cả hai có thể thay đổi mà không ảnh hưởng đến nhau.

  • Khắc phục vấn đề kết hợp giữa lớp cha và lớp con, giúp giảm sự phức tạp trong thiết kế và giúp mở rộng mã nguồn một cách linh hoạt hơn.

  • Cung cấp khả năng thay thế và tái sử dụng implementation mà không cần sửa đổi code của lớp trừu tượng.

Ý tưởng chính của Pattern

Ý tưởng chính của Bridge Pattern là sử dụng "cầu nối" giữa abstraction và implementation. Thay vì một lớp trừu tượng kiểm soát và mở rộng từ một lớp cụ thể (lớp thực thi), mẫu thiết kế này đề xuất việc tạo ra một interface (cầu nối) giữa chúng. Khi cần mở rộng chức năng, bạn có thể thêm vào phía abstraction mà không ảnh hưởng đến phía implementation và ngược lại. Nhờ có "cầu nối" này, việc thay đổi và phát triển mã nguồn trở nên linh hoạt và ít gặp rủi ro hơn.

Đặt vấn đề

Hãy tưởng tượng bạn có một lớp Vehicle với hai subclass là BicycleBikeMotorBike. Bây giờ, bạn muốn mở rộng tính năng bằng cách thêm màu sắc cho mỗi loại phương tiện, và bạn tạo ra hai thuộc tính là RedBlue. Với cách tiếp cận này, bạn sẽ phải tạo ra tổng cộng bốn lớp con như BlueBicycleBikeRedMotorBike.

Vehicle
BicycleBike
MotorBike
Red
Blue
BlueBicycleBike
RedBicycleBike
BlueMotorBike
RedMotorBike

Khi bạn muốn thêm một loại phương tiện hoặc một màu sắc mới, bạn sẽ cần tạo thêm nhiều lớp con, làm cho hệ thống trở nên phức tạp và khó kiểm soát.

Giải pháp

Vấn đề ở đây là chúng ta đang cố gắng tích hợp quá nhiều tính năng vào một lớp trừu tượng, trong khi mỗi tính năng đều có tiềm năng phát triển theo hướng riêng biệt.

is a
is a
has a
1
1
is a
is a
Vehicle
+Color color
+void manage()
Color
+void bePainted()
BicycleBike
+void manage()
MotorBike
+void manage()
Red
+void bePainted()
Blue
+void bePainted()

Bridge Pattern giải quyết vấn đề này bằng cách tách biệt lớp trừu tượng (abstraction) và các đối tượng thực thi (implementation), sau đó kết nối chúng lại với nhau thông qua một "cầu" (bridge). Trong ví dụ này, một phương tiện sẽ có một thuộc tính màu sắc, tạo ra mối quan hệ "has-a" (có một) thay vì "is-a" (là một).

Cấu Trúc

is a
has a
1
1
is a
is a
Abstraction
+Implementor implementor
+operation() : void
Implementor
+operationImpl() : void
ConcreteImplementorA
+operationImpl() : void
ConcreteImplementorB
+operationImpl() : void
RefinedAbstraction
+operation() : void
  1. The Abstraction (Abstraction): Lớp cơ sở cung cấp mức độ trừu tượng cho việc quản lý các công việc do các đối tượng cụ thể thực hiện (Implementation).

  2. The Implementation (Implementor): Giao diện định nghĩa các tác vụ cần thiết cho lớp trừu tượng. Đây thường là một giao diện xác định các tác vụ cần thiết cho lớp trừu tượng.

  3. Concrete Implementations (ConcreteImplementor): Các lớp này chứa logic cụ thể và thực hiện các tác vụ được định nghĩa bởi Implementor.

  4. Refined Abstractions (RefinedAbstraction): Các lớp con của Abstraction thực hiện và mở rộng các phương thức được xác định trong lớp Abstraction.

Cách triển khai

Bước 1: Xác định Abstraction và Implementation

Đầu tiên, ta cần phân biệt giữa abstractions (trừu tượng) và implementations (thực thi).

// Abstraction public abstract class Shape { protected Color color; public Shape(Color color) { this.color = color; } public abstract void draw(); } // Implementation public interface Color { void applyColor(); }

Bước 2: Mở rộng Abstraction

Chúng ta có thể mở rộng abstraction để tạo ra các phân lớp khác nhau.

public class Circle extends Shape { public Circle(Color color) { super(color); } @Override public void draw() { System.out.print("Draw Circle in "); color.applyColor(); } } public class Square extends Shape { public Square(Color color) { super(color); } @Override public void draw() { System.out.print("Draw Square in "); color.applyColor(); } }

Bước 3: Cung cấp các Implementations cụ thể

public class RedColor implements Color { @Override public void applyColor() { System.out.println("Red color."); } } public class BlueColor implements Color { @Override public void applyColor() { System.out.println("Blue color."); } }

Bước 4: Sử dụng Bridge Pattern

public class BridgePatternDemo { public static void main(String[] args) { Shape redCircle = new Circle(new RedColor()); Shape blueSquare = new Square(new BlueColor()); redCircle.draw(); blueSquare.draw(); } }

Khi chạy đoạn mã trên, kết quả sẽ là:

Draw Circle in Red color. Draw Square in Blue color.

Ví dụ áp dụng Bridge Pattern

Để hiểu rõ hơn về cách Bridge Pattern hoạt động, hãy xem xét ví dụ về một hệ thống ngân hàng cung cấp các loại tài khoản khác nhau:

Account.java

public interface Account { void openAccount(); }

CheckingAccount.java

public class CheckingAccount implements Account{ @Override public void openAccount() { System.out.println("Opening a Checking Account!"); } }

TutorialAccount.java

public class TutorialAccount implements Account{ @Override public void openAccount() { System.out.println("Please select your language"); } }

Bank.java

public abstract class Bank { protected Account account; public Bank(Account account) { this.account = account; } public abstract void openAccount(); }

MMBank.java

public class MMBank extends Bank { public MMBank(Account account) { super(account); } @Override public void openAccount() { System.out.println("Welcome to MMBank"); account.openAccount(); } }

TPBank.java

public class TPBank extends Bank { public TPBank(Account account) { super(account); } @Override public void openAccount() { System.out.println("Welcome to TPBank"); account.openAccount(); } }

demo.java

public class demo { public static void main(String[] args) { Bank tpBank = new TPBank(new TutorialAccount()); tpBank.openAccount(); System.out.println(); Bank mmBank = new MMBank(new CheckingAccount()); mmBank.openAccount(); } }

Kết quả khi chạy chương trình:

Welcome to TPBank Please select your language Welcome to MMBank Opening a Checking Account!

Như bạn thấy trong ví dụ trên, Bank là một lớp trừu tượng kết hợp với interface Account. Các lớp cụ thể như TPBankMMBank kế thừa từ lớp Bank và quyết định cách họ muốn mở tài khoản dựa trên loại tài khoản cụ thể (như CheckingAccount hoặc TutorialAccount). Nhờ sử dụng Bridge Pattern, chúng ta có thể mở rộng cả hai hệ thống (loại ngân hàng và loại tài khoản) một cách độc lập mà không làm ảnh hưởng đến nhau.

So sánh

1. Bridge vs Adapter:

  • Bridge: Như chúng ta đã biết, mục tiêu chính của Bridge Pattern là tách rời abstraction (trừu tượng) ra khỏi implementation (thực thi) của nó, giúp cho cả hai có thể thay đổi độc lập.

  • Adapter: Mẫu thiết kế này cho phép các đối tượng với interfaces không tương thích có thể làm việc cùng nhau thông qua một lớp trung gian.

2. Bridge vs Composite:

  • Bridge: Tách rời abstraction và implementation để chúng phát triển độc lập.

  • Composite: Cung cấp một cách để bạn có thể làm việc với các đối tượng đơn lẻ hoặc với nhóm các đối tượng theo cùng một cách.

3. Bridge vs Decorator:

  • Bridge: Phân tách interface (trừu tượng) và thực thi, cho phép chúng thay đổi độc lập.

  • Decorator: Thêm các trách nhiệm cho đối tượng mà không cần sửa đổi chúng, giữ nguyên interface của đối tượng và thêm chức năng mở rộng.

4. Bridge vs Facade:

  • Bridge: Đảm bảo tính linh hoạt giữa abstraction và implementation bằng cách tách chúng ra.

  • Facade: Cung cấp một giao diện đơn giản hoá cho một hệ thống con, giúp giảm sự phức tạp khi giao tiếp với các hệ thống phức tạp.

5. Bridge vs Proxy:

  • Bridge: Tập trung vào việc tách rời và linh hoạt giữa abstractions và implementations.

  • Proxy: Cung cấp một đại diện cho một đối tượng khác, kiểm soát việc truy cập đến đối tượng gốc.

Kết luận

Bridge Pattern là một mẫu thiết kế hiệu quả giúp tách rời các khía cạnh trừu tượng và thực thi của một lớp, giúp chúng có thể thay đổi và phát triển một cách độc lập. Điều này không chỉ giúp giảm thiểu sự phức tạp khi mở rộng hệ thống mà còn cung cấp khả năng linh hoạt hơn trong việc quản lý và mở rộng code.

Last modified: 24 May 2024