標籤:

設計模式之組合模式

題外話:本文的代碼我放在 Github 上,感興趣的可以去下載使用,在閱讀本文之前希望你熟悉 Java 語法基礎。

定義:將對象組合成樹形結構以表示「部分-整體」的層次結構。組合模式使得用戶對待單個對象或組合對象的使用具有一致性。

類別:結構型模式

舉個很常見的例子:文件系統

文件系統由文件和目錄組成,每個文件里裝有內容,而每個目錄的內容可以有文件和目錄,目錄就相當於是由單個對象或組合對象組合而成,如果你想要描述的是這樣的數據結構,那麼你就可以使用組合模式。

類圖表示:

組成元素:

  1. 抽象構件角色(Composite):是組合中對象聲明介面,實現所有類共有介面的默認行為。

  2. 樹葉構件角色(Leaf):上述提到的單個對象,葉節點沒有子節點。
  3. 樹枝構件角色(Composite):定義有子部件的組合部件行為,存儲子部件,在Component介面中實現與子部件有關的操作。

  4. 客戶端(Client):使用 Component 部件的對象。

通過上面的組合模式就可以構建出這樣的數據結構:

用 Java 代碼表示:

抽象構件:

abstract class Component {n public abstract void operation();n public void add(Component c) {ntthrow new UnsupportedOperationException();n }n public void remove(Component c) {ntthrow new UnsupportedOperationException();n }n public Component getChild(int i) {ntthrow new UnsupportedOperationException();n }n}n

UnsupportedOperationException 是為了 Leaf 在繼承之後不用重寫該方法,因為這些方法是 Composite 對象需要重寫的,而單個對象不需要。

Leaf 類:

class ConcreteComponent1 extends Component {n public void operation() {ntSystem.out.println("operation of concrete component 1 ");n }n}nnclass ConcreteComponent2 extends Component {n public void operation() {ntSystem.out.println("operation of concrete component 2 ");n }n}nnclass ConcreteComponent3 extends Component {n public void operation() {ntSystem.out.println("operation of concrete component 3 ");n }n}n

組合類:

import java.util.ArrayList;nnclass Composite extends Component {n private ArrayList<Component> children;n public Composite() {ntchildren = new ArrayList<Component>();n }n public void operation() {ntfor(Component child: children) {nt child.operation();nt}n }nn public void add(Component c) {ntchildren.add(c);n }nn public void remove(Component c) {ntchildren.remove(c);n }nn public Component getChild(int i) {ntreturn children.get(i);n }n}n

客戶端調用:

public class Client {n public static void main(String[] args) {ntComponent c1 = new ConcreteComponent1();ntComponent c2 = new ConcreteComponent2();ntComponent c3 = new ConcreteComponent3();nntComponent c = new Composite();ntc.add(c1);ntc.add(c2);ntc.add(c3);ntc.operation();nntc.remove(c2);ntc.operation();n }n}n

運行結果:

適用性:

  1. 你想表示對象的部分-整體層次結構

  2. 你希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。

組合模式與之前講的裝飾器模式很像,都是通過在類中存儲成員變數來完成一些功能上的擴展,那麼它們之間有什麼不同呢?

  • 每一個裝飾器類只有含有一個組件,即沒有對象聚合,而每個組合類可以含有多個組件,即 Composite。
  • 裝飾器模式傾向於在原有對象的基礎上添加新的功能,組合模式傾向於對原有對象的功能進行組合使用。

考慮下面的場景:

你被要求開發一個簡單的圖形庫。初始要求是:

  • 圖形庫必須能夠處理基礎圖形,如線和圓。
  • 圖形庫必須允許複合和基礎圖形的遞歸複合,以便繪圖可以由多種圖形組成。
  • 需要提供操作以允許添加,移除,顯示和圖形組件。

思路很清晰,圖形分為基礎圖形和組合圖形,用組合模式再合適不過了。

用 Java 代碼表示:

基礎圖形:

abstract class GraphicsObject {n public abstract void draw();n public void add(GraphicsObject object) {ntthrow new UnsupportedOperationException();n }n public void remove(GraphicsObject object) {ntthrow new UnsupportedOperationException();n }n}nnclass Circle extends GraphicsObject {n public void draw() {ntSystem.out.println("draw circle");n }n}nnclass Line extends GraphicsObject {n public void draw() {ntSystem.out.println("draw line");n }tn}nnclass Rectangle extends GraphicsObject {n public void draw() {ntSystem.out.println("draw rectangle");n }tn}n

組合圖形:

import java.util.ArrayList;nnclass ComposedGraphicsObject extends GraphicsObject {n private ArrayList<GraphicsObject> components;n public ComposedGraphicsObject() {ntcomponents = new ArrayList<GraphicsObject>();n }n @Overriden public void add(GraphicsObject object) {ntcomponents.add(object);n }n @Overriden public void remove(GraphicsObject object) {ntcomponents.remove(object);n }n public void draw() {ntfor(GraphicsObject component: components) {n tcomponent.draw();nt}n }n}n

圖形庫:

import java.util.ArrayList;nnclass GraphicsLibrary {n private ArrayList<GraphicsObject> components;n public GraphicsLibrary() {ntcomponents = new ArrayList<GraphicsObject>();ntinitData();n }n public void initData() {ntGraphicsObject line = new Line();ntGraphicsObject circle = new Circle();ntGraphicsObject rectangle = new Rectangle();nnt//添加基礎圖形到圖形庫中ntcomponents.add(line);ntcomponents.add(circle);ntcomponents.add(rectangle);nttnt//創建並添加組合圖形到圖形庫中ntGraphicsObject composite = new ComposedGraphicsObject();ntcomposite.add(line);ntcomposite.add(rectangle);ntcomponents.add(composite);nn }n public ArrayList<GraphicsObject> getGraphicsObjects() {ntreturn components;n }n}n

客戶端調用:

class Client {n public static void main(String[] args) {ntGraphicsLibrary gl = new GraphicsLibrary();nnt//使用基礎圖形 linentSystem.out.println("第一個圖形:");ntgl.getGraphicsObjects().get(0).draw();nnt//使用組合圖形 compositentSystem.out.println("第二個圖形:");ntgl.getGraphicsObjects().get(3).draw();n }n}n

運行結果:


推薦閱讀:

設計模式之工廠模式
PyQt信號槽的Python實現
Design Pattern 劃分方式是對設計的邏輯思考
編寫可維護代碼之「中間件模式」
一種Python全局配置規範以及其魔改

TAG:设计模式 |