3.2. Các mẫu dáng thiết kế (Mẫu thiết kế)
3.2.4. Các mẫu cấu trỳc(Structural Mẫu)
Các mẫu cấu trúc được quan tâm về các lớp và các đối tượng như thế nào để hợp thành một cấu trúc lớn hơn. Các mẫu lớp cấu trúc đều dùng tớnh kế thừa để tạo giao diện hoặc thực hiện. Structural đối tượng mô tả các phương pháp để tạo các đối tượng thu được nhiều chức năng mới. Giữa các mẫu cấu trúc cú cỏc thành phần giống nhau, đặc biệt là thành phần tham gia và cộng tác của chúng. Điều này là có thể vỡ cỏc mẫu cấu trúc dựa trên một bộ nhỏ giống nhau của các cơ chế ngôn ngữ về mã cấu trúc và sự vật.
Có thể chia chúng thành 2 loại:
Structural class pattern: Sử dụng tính kế thừa để tạo các giao diện hay các thực hiện: ví dụ, ta thừa kế trộn 2 hay nhiều lớp thành một lớp. Lớp tạo ra chứa tất cả các thuộc tính của các lớp cha của nó.
Structural object pattern: là phương pháp để hợp các đối tượng để thực hiện chức năng mới.
Trong các mẫu cấu trúc cú cỏc mẫu mà tụi đó nghiên cứu sau:
Adapter mẫu Bridge mẫu Composite mẫu Decorator mẫu Facade mẫu Flyweight mẫu Proxy mẫu 3.2.4.1. Adapter mẫu 3.2.4.1.1 Mục đích
Chuyển đổi giao diện của một lớp sang giao diện khác mà client muốn. Cho phép các lớp có giao diện không tương thích làm việc với nhau.
3.2.4.1.2 Ví dụ:
Một soạn thảo đồ hoạ, giúp người dùng có thể vẽ hoặc sắp xếp các thành phần đồ hoạ như là đường thẳng, text, đa giác... vào các tranh vẽ hoặc các biểu đồ. Vấn đề trừu tượng chính của soạn thảo vẽ ở đây là đối tượng đồ hoạ, hình dáng có thể tự sửa đổi được. Giao diện cho các vấn đề
đồ hoạ ở đây được định nghĩa bởi một lớp trừu tượng gọi là Shape. Soạn thảo vẽ định nghĩa một lớp con của Shape cho từng loại như LineShape cho đường kẻ, PolygonShape cho đa giác...
Các lớp ứng với các hình dáng hình hoạ cơ bản như LineShape, PolygonShape là đơn giản hơn trong việc cài đặt vì cỏc khả năng vẽ và sửa đổi của chúng là hạn chế. Nhưng một lớp con TextShape cho phép hiển thị và sửa đổi text rất khó cài đặt, do việc sửa đổi text đến cỏc phộp cập nhật màn hình quản lý bộ đệm phức tạp.
Trong khi đó, bộ dụng cụ trong giao diện người dùng cung cấp lớp TextView cho hiển thị và soạn thảo. Ở đây ta muốn sử dụng lại TextView để thực hiện TextShape, nhưng dụng cụ không được thiết kế với Shape nên không thể sử dụng đối tượng TextView và TextShape một cách tích hợp.
Như vậy yêu cầu ở đây đặt ra là làm thế nào để các lớp sẵn có và không liên quan như TextView và TextShape có thể làm việc với nhau trong khi giao diện không tương thích với nhau.
Một giải pháp đặt ra là có thể thay đổi lớp TextView để cho nó phù hợp với giao diện Shape, nhưng sẽ không thực hiện nếu không có mã nguồn trong bộ dụng cụ. Chính vì thế, thay vì định nghĩa TextShape để thích ứng với giao diện TextView với giao diện Shape. Chúng ta có thể định nghĩa điều này theo 2 cách: bằng cách kế thừa giao diện Shape và thực hiện TextView hoặc kết nối thể hiện TextView vào một TextShape và cài đặt TextShape dưới dạng giao diện của TextView. Cả hai phương pháp này tương ứng với hai phiên bản của mẫu Adapter: class Adapter pattern, và Object Adapter Pattern.
3.2.4.1.3 Ứng dụng
Muốn sử dụng một lớp hiện hành và giao diện của nó nhưng không phù hợp với cái bạn cần.
Muốn tạo một lớp sử dụng lại mà các kết nối với các lớp không liên quan, không biết trước, nghĩa là các lớp không cần phải có giao diện tương thích.
Cần sử dụng một số các lớp con hiện hành, nhưng nó được ứng dụng trong thực tế để điều hợp giao diện của chúng bằng việc phân lớp. Một đối tượng Adapter có thể điều hợp giao diện của lớp cha.
Phương pháp I: Một lớp adapter sử dụng tính kế thừa để thớc ứng một giao diện tới giao diện khác.
Một đối tượng adapter dựa trên tổ hợp đối tượng.
3.2.4.1.5 Thành phần:
Target : định nghĩa giao diện domain-specific mà Client sử dụng. Client : Cộng tác với cỏc đối tượng tuân theo giao diện Target .
Adaptee : Định nghĩa một giao diện có sẵn cần thiết cho việc thích nghi. Adapter:Giao diện này cần phải sửa đổi cho phù hợp với giao diện Target.
3.2.4.1.6 Các cộng tác
Client gọi các lệnh trong thể hiện Adapter. Từ đó, adapter gọi các lệnh Adaptee để thực hiện yêu cầu.
Client Target
Request() Adapter Request() Adaptee SpecificRequest() Return uniqueInstance (Implementation) Client Target Request() Adapter Request() Adaptee SpecificRequest() Return uniqueInstance ad aptee
3.2.4.1.7 Kết quả.
Class Adapter và object Adapter có nhiều yếu tố để đánh giá khác nhau để đạt được hiệu quả tốt nhất. Việc làm cho Adapter tương thích với Target được làm cho một lớp cụ thể. Dẫn đến, một lớp adapter sẽ không hoạt động khi chúng ta muốn điều hợp một lớp và các lớp con của nó. Điều hợp Adapter tới Target bằng cách chuyển đến lớp Adapter cụ thể. Cho phép Adapter ghi đè một số hoạt động của Adapter, từ khi Adapter là một lớp con của Adaptee.
Giới thiệu duy nhất một đối tượng, và không cần điểm gián tiếp nào để nhận đến adaptee.
Một đối tượng adapter:
Cho phép một adapter làm việc với nhiều adaptee.
Làm cho khó ghi đố các hàm của Adaptee hơn, nó yêu cầu tạo lớp con Adaptee và bắt Adapter tham chiếu đến lớp con chứ không phải là bản thân Adaptee.
Một số vấn đề khi sử dụng Adapter mẫu:
Adapter biến đổi trong một lượng công việc chúng thực hiện để tương thích Adatee tới giao diện Target. Adapter là không trong suốt với client.
3.2.4.1.8 Cài đặt.
Cài đặt lớp Adater trong C++ : Adapter có thể kế thừa chung từ Target và riêng từ Adaptee. Do đó Adapter là một dạng con thuộc Target chứ không thuộc Adaptee.
Sử dụng các thao tác trừu tượng. Sử dụng các đối tượng thành phần. Các Adapter đã được tham số hoá.
3.2.4.1.9 Các mẫu liên quan:
Bridge có cấu trúc tương tự như một đối tượng adapter, nhưng Bridge có nội dung khỏc: Nó được hiểu là để phân chia một giao diện từ việc thực hiện của nó nên có thể biến đổi rõ ràng và độc lập. Một adapter được hiểu là để thay đổi một giao diện của đối tượng sẵn có.
Decorator tăng cường đối tượng khác mà không cần thay đổi giao diện của nó. Một Decorator vì thế sẽ trong suốt hơn đối với ứng dụng
hơn là một adapter. Từ đó đưa ra kết quả, Decorator hỗ trợ các thành phần đệ quy, mà nó không có hỗ trợ cho một adapter trong suốt.
Proxy định nghĩa một biểu diễn hoặc thay thế cho đối tượng khác và không thay đổi giao diện của nó.
3.2.4.2. Bridge mẫu
3.2.4.2.1 Mục đích
Phân tách việc trừu tượng hoá khỏi các cài đặt của chúng để cho cả hai có thể biến đổi một cách độc lập.
3.2.4.2.2 Ví dụ
Việc cài đặt của vấn đề trừu tượng hoá trong cửa sổ Window trong bộ dụng cụ giao diện người dùng, cho phép các user có thể ghi các ứng dụng làm việc trong cả hai hệ thống X Window System và Presentation Manager. Sử dụng tính kế thừa, chúng ta định nghĩa một lớp Window, các lớp con XWindow và PMWindow cài đặt giao diện Window cho các nền khác nhau.
Nhưng chính phương pháp này có hai điều hạn chế lớn nhất, đó là:
- Không thuận tiện khi mở rộng Window để bao hàm các dạng khác của window hoặc các nền mới. Tưởng tượng là một lớp con IconWindow của Window chỉ ra bởi các icon trong Window. Để hỗ trợ Icon Window cho cả hai nền này, chúng ta cài đặt 2 lớp mới, XIconWindow và PMIconWindow. Trong trường hợp xấu nhất, chúng ta sẽ định nghĩa 2 lớp cho mọi cửa sổ. Như vậy cần một nền thứ 3 yêu cầu lớp con Window mới cho tất cả các dạng cửa sổ.
- Làm cho mã nguồn Client độc lập với nền. Bất kỳ khi nào client tạo một cửa sổ, nó khỏi tạo một lớp thực hiện, mà nó chỉ ra cài đặt. Trong trường hợp này, ạo một đối tượng XWindow kết nối với Window cho việc cài đặt X Window, tạo mã nguồn client độc lập với cài đặt X Window, chính vì thế, nó rất khó để chuyển mã nguồn client tới các nền khác.
Khi áp dụng mẫu Bridge, nó lập địa chỉ những vấn đề này bằng cách đặt Window và cài đặt của nó trong biểu đồ lớp phân chia. Chỉ có một lớp kế thừa cho các cửa sổ giao diện (Window, IconWindow, TransientWindow) và biểu đồ lớp phân chia cho các cài đặt cửa sổ chỉ
ra nền, coi WindowImp là gốc. Lớp con XWindowImp cung cấp một cài đặt dựa trên X Window System.
Tất cả các lớp con Window được cài đặt trong các thao tác ảo từ giao diện WindowImp. Điều này tách riêng các cửa sổ khỏi các cài đặt. Mối quan hệ giã Window và WindowImp như một cầu nối, do nó bắc cầu giữa vấn đề trừu tượng này và việc cài đặt của nó, cho phép chúng biến đổi một cách độc lập.
3.2.4.2.3 Ứng dụng
Cần tránh một kết nối cố định giữa vấn đề ảo và việc cài đặt của nó. Cả vấn đề ảo và việc cài đặt của nó có thể mở rộng việc phân lớp con. Trong trường hợp này Bridge cho phép bạo tổ hợp các vấn đề ảo và các cài đặt khác nhau và mở rộng chúng một cách độc lập.
Thay đổi cài đặt của một vấn đề ảo có thể không ảnh hưởng đến client; có nghĩa là mã của chúng không cần phải dịch lại.
Muốn ẩn việc thực hiện của vấn đề ảo hoàn toàn từ các client.
Muốn dùng chung cài đặt giữa nhiều đối tượng, và điều này có thể được ẩn từ client.
3.2.4.2.4 Cấu trúc:
3.2.4.2.5 Thành phần:
Abstraction:
o Định nghĩa một giao diện trừu tượng.
Client Abstraction Operation() Abstraction Operation() RelinedAbstraction imp->OperationImp() ConcreteimplementorA OperationImp() ConcreteimplementorB OperationImp()
o Duy trì một tham chiếu tới một đối tượng của dạng Implementor.
RefinedAbstraction :
o Mở rộng một giao diện được định nghĩa bởi Abstraction.
Implementor:
o Định nghĩa một giao diện để cài đặt các lớp. Giao diện này không cần phải thực hiện một cách chính xác tới giao diện của Abstraction; thực tế hai giao diện có quá nhiều điểm khác nhau. Điển hình giao diện Implementor cung cấp các thao tác cơ bản, và Abstraction định nghĩa các thao tác mức cao dựa trên những ưu tiên này.
ConcretImplementor:
o Thực hiện giao diện Implementor và định nghĩa cài đặt cụ thể. của nó.
3.2.4.2.6 Kết quả
Phân tách giao diện và cài đặt. Do việc thực hiện của vấn đề ảo có thể được định dạng tại thời gian chạy. Phân tách được Abstraction và Implementation cũng loại bỏ được sự phụ thuộc của thời gian biên dịch vào cài đặt, thay đổi việc cài đặt lớp không yêu cầu phải biên dịch lại lớp Abstraction và các client của nó.
Khả năng mở rộng được cải thiện. Có thể mở rộng biểu đồ Abstraction và Implementation một cách độc lập.
Ẩn đi các chi tiết cài đặt từ Client.
3.2.4.2.7 Cài đặt
Trong quá trình thực hiện khi áp dụng Bridge mẫu vào, sẽ phát sinh một số vấn đề sau :
Chỉ có một Implementor.
Tạo đúng đối tượng Implementation Sử dụng chung Implementor.
Sử dụng tính đa kế thừa.
Abstract Factory có thể tạo và cấu hình một phần Bridge.
Adapter mẫu lớn hơn toward việc tạo các lớp không phụ thuộc làm việc cùng nhau. Nó thường được áp dụng vào hệ thống sau khi chỳng đó được thiết kế. Bridge, trong một khía cạnh nào đó, được sử dụng up-front trong thiết kế để cho phộp cỏc trừu tượng hoá và việc cài đặt biến đổi một cách độc lập.
3.2.4.3. Composite
3.2.4.3.1 Mục đích
Tạo nên một cách tổng thể các đối tượng thành cấu trúc cây để biểu diễn các hệ thống part-whole. Composite cho phép các client sử dụng các đối tượng và các thành phần riêng lẻ của các đối tượng thống nhất.
3.2.4.3.2 Ví dụ
Ứng dụng đồ hoạ như soạn thảo vẽ và hệ thống biểu diễn dưới dạng bản đồ cho phép người dùng xây dựng một biểu đồ phức tạp từ những thành phần đơn giản. Người dùng có thể nhúm cỏc thành phần để tổ chức thành thành phần lớn hơn. Một cách thực hiện đơn giản là có thể định nghĩa các lớp cho các mẫu đồ hoạ như Text, Line, và các lớp cú cỏc hoạt động này.
Khi sử dụng phương pháp này, sẽ xuất hiện một vấn đề: Mã nguồn mà sử dụng các lớp này phải xử lý được màu gốc và các đối tượng trong nội dung đó một cách khác nhau. Để phân biệt những đối tượng này sẽ làm cho hệ thống phức tạp hơn. Mẫu Composite mô tả làm thế nào để sử dụng thành phần đệ quy nờn cỏc client không cần phải tạo sự khác biệt đó.
Nhưng vấn đề chủ yếu ở đây là: một lớp ảo biểu diễn cả gốc và nội dung của nó. Đối với hệ thống đồ hoạ, lớp này là Graphic, Graphic khai báo các thao tác Draw, dùng để chỉ ra các đối tượng đồ hoạ. Nó cũng khai báo các thao tác mà tất cả các thành phần của nó sử dụng chung, ví dụ như thao tác truy xuất và quản lớ cỏc lỏ con của nó.
Các lớp con như là Line, Rectangle, và Text, định nghĩa các đối tượng đồ hoạ cơ bản. Những lớp này cài đặt thao tỏcDraw để vẽ các đường, hình chữ nhật, và dạng text, từ đó các đối tượng đồ hoạ cơ bản không có các đồ hoạ con, không có lớp con nào trong số đó cài đặt các thao tác con- quan hệ. Do lớp Picture định nghĩa một kết tập với đối tượng Graphic, nên Picture cài đặt Draw để gọi Draw trong các con của nó, và nó cài đặt các thao tác
con-quan hệ. Do giao diện Picture tương thích với với giao diện Graphic, đối tượng Picture có thể tổ hợp các đệ quy Picture khác.
3.2.4.3.3 Ứng dụng
Muốn biểu diễn các biểu đồ part-whole của các đối tượng.
Muốn client có thể bỏ qua sự khác nhau giữa các composition của các đối tượng và đối tượng riêng lẻ. Client sẽ vận dụng tất cả các đối tượng trong cấu trúc thành phần một cách đồng bộ.
3.2.4.3.4 Cấu trúc:
Các đối tượng typically Composite có thể được quan sát dưới dạng:
Client Component Operation Add(Component) Remove(Compone nt) GetChild(int) Composite Operation() Add(Component) Remove(Compone nt) GetChild(int) Leal
Operation() For all in children
g.Operation(); aPicture
aLine aPicture
aText aLine aRectangle
3.2.4.3.5 Thành phần
Component:
o Khai báo một giao diện cho các đối tượng trong composition
o Cài đặt mặc định hàm cho giao diện chung tới tất cả các lớp con của nó.
o Khai báo một giao diện cho việc truy xuất và quản lớ cỏc thành phần con của nó.
o Định nghĩa một giao diện cho việc truy xuất một thành phần cha trong cấu trúc đệ quy, và cài đặt nó nếu nó thích hợp.
Leaf:
o Biểu diễn các đối tượng lá trong thành phần. Một lá không có con nào.
o định nghĩa hoạt động của các đối tượng ưu tiên trong thành phần.
Composite
o Định nghĩa hoạt động cho các thành phần chứa các lớp con.
o Lưu các thành phần con.
o Cài đặt các thao tác con-quan hệ trong giao diện Component.
Client.
aComposite
aleaf aLeaf aComposite
aLeaf aLeaf aleaf
o vận dụng các đối tượng vào thành phần thông qua giao diện Component.
3.2.4.3.6 Kết quả.
Định nghĩa các biểu đồ lớp bao hàm cả các đối tượng ưu tiên và các đối tượng thành phần. Đối tượng ưu tiên có thể được kết cấu vào nhiều đối tượng phức tạp. Bất cứ khi nào mã client muốn một đối tượng ưu tiên, nó cũng có thể sử dụng đối tượng thành phần.
Tạo client đơn giản. Client có thể xử lý các cấu trúc thành phần và các đối tượng riêng lẻ một cách không đồng bộ.
Dễ dàng thêm vào các dạng mới của các thành phần. Có thể làm cho thiết kế tổng quát hơn.
3.2.4.3.7 Phối hợp cộng tác
Các client sử dụng giao diện lớp Component để tương thích với các đối tượng trong cấu trúc thành phần. Nếu nơi nhận là nút Leaf, thỡ cỏc yêu cầu được nắm giữ một cách trực tiếp. Nếu nơi nhận là Composite, thỡ cỏc yêu