close up photo of programming of codes

codecungnhau.com

Một trang web về kỹ thuật lập trình

Design Patterns: Bridge

Mục tiêu

Bridge là một mẫu thiết kế cấu trúc cho phép bạn chia một lớp lớn hoặc một tập hợp các lớp có liên quan chặt chẽ thành hai phân cấp riêng biệt – trừu tượng và hiện thực – có thể được phát triển độc lập với nhau.

Đặt vấn đề

Tính trừu tượng (abstraction)? Hiện thực (implementation) ? Nghe có vẻ đáng sợ? Hãy bình tĩnh và hãy xem xét một ví dụ đơn giản sau

Giả sử bạn có một lớp hình học Shape với một cặp lớp con: CircleSquare. Bạn muốn mở rộng hệ thống phân cấp lớp này để kết hợp với màu sắc, vì vậy bạn dự định tạo các lớp con RedBlue. Tuy nhiên, vì bạn đã có hai lớp con, bạn sẽ cần tạo bốn kết hợp lớp như BlueCircleRedSquare.

Số lượng kết hợp lớp tăng lên theo tiến triển hình học.

Việc thêm các loại hình dạng và màu sắc mới vào hệ thống phân cấp sẽ phát triển nó theo cấp số nhân. Ví dụ: để thêm hình tam giác, bạn cần giới thiệu hai lớp con, mỗi lớp một màu. Và sau đó, việc thêm một màu mới sẽ yêu cầu tạo ba lớp con, một lớp cho mỗi kiểu hình dạng. Càng đi xa, nó càng trở nên tồi tệ.

Giải pháp

Sự cố này xảy ra vì chúng ta đang cố gắng mở rộng các lớp hình dạng theo hai chiều độc lập: theo hình thức và theo màu sắc. Đó là một vấn đề rất phổ biến trong kế thừa.

Mẫu Bridge cố gắng giải quyết vấn đề này bằng cách chuyển từ kế thừa sang đối tượng thành phần . Điều này có nghĩa là bạn trích xuất một trong các chiều vào một hệ thống phân cấp lớp riêng biệt, để các lớp ban đầu sẽ tham chiếu đến một đối tượng của hệ thống phân cấp mới, thay vì có tất cả trạng thái và hành vi của nó trong một lớp.

Bạn có thể ngăn chặn sự bùng nổ của hệ thống phân cấp lớp bằng cách chuyển nó thành một số hệ thống phân cấp có liên quan.

Theo cách tiếp cận này, ta có thể trích xuất mã liên quan đến màu sắc thành lớp riêng của nó với hai lớp con: RedBlue. Sau đó, lớp Shape nhận được một trường tham chiếu trỏ đến một trong các đối tượng màu. Bây giờ hình dạng có thể ủy thác mọi công việc liên quan đến màu sắc cho đối tượng màu được liên kết. Tham chiếu đó sẽ hoạt động như một cầu nối giữa các lớp ShapeColor. Từ giờ trở đi, việc thêm màu mới sẽ không yêu cầu thay đổi phân cấp lớp và ngược lại.

Trừu tượng (abstraction) và Hiện thực (implementation)

Trừu tượng (còn gọi là giao diện) là một lớp điều khiển cấp cao cho một số thực thể. Lớp này không được phép tự thực hiện bất kỳ công việc thực sự nào. Nó sẽ ủy thác công việc cho lớp hiện thực (còn được gọi là nền tảng). Lưu ý rằng chúng ta không nói về giao diện hoặc các lớp trừu tượng của ngôn ngữ lập trình. Chúng không phải là những thứ giống nhau.

Khi nói về các ứng dụng thực tế, phần trừu tượng có thể được thể hiện bằng giao diện người dùng đồ họa (GUI) và việc triển khai có thể là mã điều hành cơ bản (API) mà lớp GUI gọi để phản hồi lại các tương tác của người dùng.

Nói chung, bạn có thể mở rộng một ứng dụng như vậy theo hai hướng độc lập:

  • Có một số GUI khác nhau (ví dụ: được điều chỉnh cho khách hàng hoặc quản trị viên thông thường).
  • Hỗ trợ một số API khác nhau (ví dụ: để có thể khởi chạy ứng dụng trong Windows, Linux và macOS).

Trong trường hợp xấu nhất, ứng dụng này có thể trông giống như một tô mì spaghetti khổng lồ, nơi hàng trăm điều kiện kết nối các loại GUI khác nhau với các API khác nhau trên toàn bộ mã.

Thực hiện ngay cả một thay đổi đơn giản đối với một cơ sở mã nguyên khối cũng khá khó vì bạn phải hiểu rất rõ toàn bộ nội dung. Thực hiện thay đổi đối với các mô-đun nhỏ hơn, được xác định rõ ràng dễ dàng hơn nhiều.

Bạn có thể mang lại trật tự cho sự hỗn loạn này bằng cách trích xuất mã liên quan đến các kết hợp nền tảng – giao diện cụ thể thành các lớp riêng biệt. Tuy nhiên, bạn sẽ sớm phát hiện ra rằng có rất nhiều lớp thế này. Hệ thống phân cấp lớp sẽ phát triển theo cấp số nhân bởi vì việc thêm GUI mới hoặc hỗ trợ một API khác sẽ yêu cầu tạo ngày càng nhiều lớp.

Hãy thử giải quyết vấn đề này với mẫu Bridge. Nó gợi ý rằng chúng ta chia các lớp thành hai phân cấp:

  • Trừu tượng: lớp GUI của ứng dụng.
  • Hiện thực: API của hệ điều hành.
Một trong những cách để cấu trúc một ứng dụng đa nền tảng.

Đối tượng trừu tượng kiểm soát sự xuất hiện của ứng dụng, ủy quyền công việc thực tế cho đối tượng hiện thực được liên kết. Các hiện thực khác nhau có thể hoán đổi cho nhau miễn là chúng tuân theo một giao diện chung, cho phép cùng một GUI hoạt động trên Windows và Linux.

Do đó, bạn có thể thay đổi các lớp GUI mà không cần chạm vào các lớp liên quan đến API. Hơn nữa, việc hỗ trợ thêm cho một hệ điều hành khác chỉ yêu cầu tạo một lớp con trong hệ thống phân cấp hiện thực.

Cấu trúc

  1. Abstraction cung cấp logic điều khiển cấp cao. Nó dựa vào đối tượng Implementation để thực hiện công việc cấp thấp thực tế.
  2. Implementation khai báo giao diện chung cho tất cả các hiện thực cụ thể. Một Abstraction chỉ có thể giao tiếp với một đối tượng Implementation thông qua các phương thức được khai báo ở đây. Abstraction có thể liệt kê các phương thức tương tự như Implementation, nhưng thông thường nó khai báo một số hành vi phức tạp dựa trên nhiều hoạt động gốc được khai báo bởi Implementation.
  3. Concrete Implementation chứa mã dành riêng cho các nền tảng.
  4. Refined Abstraction cung cấp các biến thể của logic điều khiển. Giống như lớp cha của nó, nó làm việc với các implementation khác nhau thông qua giao diện Implementation chung.
  5. Thông thường, Client chỉ quan tâm đến việc làm việc với abstraction. Tuy nhiên, nhiệm vụ của client là liên kết đối tượng abstraction với một trong các đối tượng implementation.

Khả năng áp dụng

Sử dụng mẫu Bridge khi bạn muốn phân chia và tổ chức một lớp nguyên khối có một số biến thể của một số chức năng (ví dụ: nếu lớp có thể hoạt động với các máy chủ cơ sở dữ liệu khác nhau).

Sử dụng mẫu khi bạn cần mở rộng một lớp theo một số chiều trực giao (độc lập).

Sử dụng Bridge nếu bạn cần để có thể chuyển đổi các hiện thực trong thời gian chạy.

Ưu và nhược điểm

😄😄😄

Có thể tạo các lớp và ứng dụng độc lập với nền tảng.

Client hoạt động với sự trừu tượng hóa cấp cao. Nó không hiển thị với các nền tảng chi tiết.

Nguyên tắc Mở / Đóng. Có thể giới thiệu các phần trừu tượng và hiện thực mới một cách độc lập với nhau.

Nguyên tắc Đơn Trách nhiệm. Có thể tập trung vào logic cấp cao trong phần trừu tượng và chi tiết nền tảng trong quá trình hiện thực.

🙁🙁🙁

Có thể làm cho mã phức tạp hơn bằng cách áp dụng mẫu cho một lớp có tính gắn kết cao.

Mối quan hệ với các mẫu khác

Bridge thường được thiết kế up-front, cho phép bạn phát triển các phần của ứng dụng một cách độc lập với nhau. Ngược lại, Adapter thường được sử dụng với một ứng dụng hiện có để làm cho một số lớp không tương thích hoạt động với nhau.

Bridge, State, Strategy (và ở một mức độ nào đó là Adapter) có cấu trúc rất giống nhau. Thật vậy, tất cả các mẫu này đều dựa trên hợp thành (composition), tức là ủy thác công việc cho các đối tượng khác. Tuy nhiên, chúng đều giải quyết các vấn đề khác nhau. Mẫu thiết kế không chỉ là một công thức để cấu trúc chương trình của bạn theo một cách cụ thể. Nó cũng có thể giao tiếp với các nhà phát triển khác về vấn đề mà mẫu giải quyết.

Có thể sử dụng Abstract Factory cùng với Bridge. Việc ghép nối này rất hữu ích khi một số trừu tượng được định nghĩa bởi Bridge chỉ có thể hoạt động với các hiện thực cụ thể. Trong trường hợp này, Abstract Factory có thể đóng gói các quan hệ này và ẩn sự phức tạp khỏi client.

Có thể kết hợp Builder với Bridge: lớp Director đóng vai trò trừu tượng, trong khi các builder khác nhau đóng vai trò hiện thực.

Chương trình tham khảo

C++

C#

Python


Đã đăng vào

trong

bởi

Bình luận

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *