Hướng dẫn Java Design Pattern – Bridge – GP Coder (Lập trình Java)

Một thành phần trong OOP thường có 2 phần: Phần trừu tượng (abstraction) định nghĩa các chức năng và phần thực thi (implementation) các chức năng được định nghĩa trong phần trừu tượng. Hai phần này liên hệ với nhau thông qua quan hệ kế thừa. Những thay đổi trong phần trừu tượng dẫn đến các thay đổi trong phần thực thi.

Bạn đang đọc: Hướng dẫn Java Design Pattern – Bridge – GP Coder (Lập trình Java)

Bridge Pattern được sử dụng để tách thành phần trừu tượng (abstraction) và thành phần thực thi (implementation) riêng biệt. Do đó, các thành phần này có thể thay đổi một cách độc lập mà không ảnh hưởng đến các thành phần khác. Thay vì liên hệ với nhau bằng quan hệ kế thừa, hai thành phần này liên hệ với nhau thông qua quan hệ “chứa trong” (object composition).

Bridge Pattern là gì?

Decouple an abstraction from its implementation so that the two can vary independently.

Bridge Pattern là một trong những Pattern thuộc nhóm cấu trúc (Structural Pattern). Ý tưởng của nó là tách tính trừu tượng (abstraction) ra khỏi tính hiện thực (implementation) của nó. Từ đó có thể dễ dàng chỉnh sửa hoặc thay thế mà không làm ảnh hưởng đến những nơi có sử dụng lớp ban đầu.

Điều đó có nghĩa là, ban đầu chúng ta thiết kế một class với rất nhiều xử lý, bây giờ chúng ta không muốn để những xử lý đó trong class đó nữa. Vì thế, chúng ta sẽ tạo ra một class khác và move các xử lý đó qua class mới. Khi đó, trong lớp cũ sẽ giữ một đối tượng thuộc về lớp mới, và đối tượng này sẽ chịu trách nhiệm xử lý thay cho lớp ban đầu.

Bridge Pattern khá giống với mẫu Adapter Pattern ở chỗ là sẽ nhờ vào một lớp khác để thực hiện một số xử lý nào đó. Tuy nhiên, ý nghĩa và mục đích sử dụng của hai mẫu thiết kế này hoàn toàn khác nhau:

  • Adapter Pattern hay còn gọi là Wrapper pattern được dùng để biến đổi một class/ interface sang một dạng khác có thể sử dụng được. Adapter Pattern giúp các lớp không tương thích hoạt động cùng nhau mà bình thường là không thể.
  • Bridge Pattern được sử dụng được sử dụng để tách thành phần trừu tượng (abstraction) và thành phần thực thi (implementation) riêng biệt.
  • Adapter Pattern làm cho mọi thứ có thể hoạt động với nhau sau khi chúng đã được thiết kế (đã tồn tại). Bridge Pattern nên được thiết kế trước khi phát triển hệ thống để Abstraction và Implementation có thể thực hiện một cách độc lập.

Cài đặt Bridge Pattern như thế nào?

Một Bridge Pattern bao gồm các thành phần sau:

  • Client: đại diện cho khách hàng sử dụng các chức năng thông qua Abstraction.
  • Abstraction : định ra một abstract interface quản lý việc tham chiếu đến đối tượng hiện thực cụ thể (Implementor).
  • Refined Abstraction (AbstractionImpl) : hiện thực (implement) các phương thức đã được định ra trong Abstraction bằng cách sử dụng một tham chiếu đến một đối tượng của Implementer.
  • Implementor : định ra các interface cho các lớp hiện thực. Thông thường nó là interface định ra các tác vụ nào đó của Abstraction.
  • ConcreteImplementor : hiện thực Implementor interface.

Ví dụ:

Một hệ thống ngân hàng cung cấp các loại tài khoản khác nhau cho khách hàng, chẳng hạn: Checking account và Saving account. Chúng ta có sơ đồ như sau:

Với cách thiết kế như vậy, khi hệ thống cần cung cấp thêm một loại tài khoản khác, chúng ta phải tạo class mới cho tất cả các ngân hàng, số lượng class tăng lên rất nhiều.

Bây giờ, chúng ta sẽ sử dụng Bridge Pattern để tái cấu trúc lại hệ thống trên như sau:

Tìm hiểu thêm: Kem chống nắng phổ rộng là gì? Nhận biết kem chống nắng phổ rộng

>>>>>Xem thêm: TỪ ĐIỂN CHÍNH TẢ SAI CHÍNH TẢ () Người bắt lỗi tiếp tục phản biện – Báo Người lao động

Với cấu trúc mới như vậy, khi có thêm một loại tài khoản mới, chúng ta đơn chỉ việc thêm vào một implement mới cho Account, các thành phần khác của Bank không bị ảnh hưởng. Hoặc cần thêm một ngân hàng mới, chẳng hạn VietinBank chúng ta chỉ cần thêm implement mới cho Bank, các thành phần khác cũng không bị ảnh hưởng và số lượng class chỉ tăng lên 1.

Code cho chương trên như sau:

Account:

public interface Account { void openAccount(); }

CheckingAccount:

public class CheckingAccount implements Account { @Override public void openAccount() { sentayho.com.vntln(“Checking Account”); } }

SavingAccount:

public class SavingAccount implements Account { @Override public void openAccount() { sentayho.com.vntln(“Saving Account”); } }

Bank:

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

VietcomBank:

public class VietcomBank extends Bank { public VietcomBank(Account account) { super(account); } @Override public void openAccount() { sentayho.com.vnt(“Open your account at VietcomBank is a “); sentayho.com.vnAccount(); } }

TPBank:

public class TPBank extends Bank { public TPBank(Account account) { super(account); } @Override public void openAccount() { sentayho.com.vnt(“Open your account at TPBank is a “); sentayho.com.vnAccount(); } }

Client:

public class Client { public static void main(String[] args) { Bank vietcomBank = new VietcomBank(new CheckingAccount()); sentayho.com.vnAccount(); Bank tpBank = new TPBank(new CheckingAccount()); sentayho.com.vnAccount(); } }

Output của chương trình trên:

Open your account at VietcomBank is a Checking Account Open your account at TPBank is a Checking Account

Lợi ích của Bridge Pattern là gì?

  • Giảm sự phục thuộc giữa abstraction và implementation (loose coupling): tính kế thừa trong OOP thường gắn chặt abstraction và implementation lúc build chương trình. Bridge Pattern có thể được dùng để cắt đứt sự phụ thuộc này và cho phép chúng ta chọn implementation phù hợp lúc runtime.
  • Giảm số lượng những lớp con không cần thiết: một số trường hợp sử dụng tính inheritance sẽ tăng số lượng subclass rất nhiều. Ví dụ: trường hợp chương trình view hình ảnh trên các hệ điều hành khác nhau, ta có 6 loại hình (JPG, PNG, GIF, BMP, JPEG, TIFF) và 3 hệ điều hành (Window, MacOS, Ubuntu). Sử dụng inheritance trong trường hợp này sẽ làm ta thiết kế 18 lớp: JpgWindow, PngWindow, GifWindow, …. Trong khi áp dụng Bridge sẽ giảm số lượng lớp xuống 9 lớp: 6 lớp ứng với từng implement của Image và 3 lớp ứng với từng hệ điều hành, mỗi hệ điều hành sẽ gồm một tham chiếu đến đối tượng Image cụ thể.
  • Code sẽ gọn gàn hơn và kích thước ứng dụng sẽ nhỏ hơn: do giảm được số class không cần thiết.
  • Dễ bảo trì hơn: các Abstraction và Implementation của nó sẽ dễ dàng thay đổi lúc runtime cũng như khi cần thay đổi thêm bớt trong tương lai.
  • Dễ dàng mở rộng về sau: thông thường các ứng dụng lớn thường yêu cầu chúng ta thêm module cho ứng dụng có sẵn nhưng không được sửa đổi framework/ứng dụng có sẵn vì các framework/ứng dụng đó có thể được công ty nâng cấp lên version mới. Bridge Pattern sẽ giúp chúng ta trong trường hợp này.
  • Cho phép ẩn các chi tiết implement từ client: do abstraction và implementation hoàn toàn độc lập nên chúng ta có thể thay đổi một thành phần mà không ảnh hưởng đến phía Client. Ví dụ, các lớp của chương trình view ảnh sẽ độc lập với thuật toán vẽ ảnh trong các implementation. Như vậy ta có thể update chương trình xem ảnh khi có một thuật toán vẽ ảnh mới mà không cần phải sửa đổi nhiều.

Sử dụng Bridge Pattern khi nào?

  • Khi bạn muốn tách ràng buộc giữa Abstraction và Implementation, để có thể dễ dàng mở rộng độc lập nhau.
  • Cả Abstraction và Implementation của chúng nên được mở rộng bằng subsclass.
  • Sử dụng ở những nơi mà những thay đổi được thực hiện trong implement không ảnh hưởng đến phía client.

Tài liệu tham khảo:

  • https://sourcemaking.com/design_patterns/bridge
  • https://refactoring.guru/design-patterns/bridge
  • https://vi.wikipedia.org/wiki/Bridge_pattern
  • https://www.javatpoint.com/bridge-pattern
  • https://www.tutorialspoint.com/design_pattern/bridge_pattern.htm
  • http://www.thejavageek.com/2016/10/20/bridge-design-pattern-implementation/

Chuyên mục: Design pattern, Structuaral Pattern Được gắn thẻ: Design pattern, Structuaral Pattern

Bình luận

bình luận

Leave a Reply

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