Java結構型設計模式之組合模式詳解
組合模式
組合模式(Composite Pattern)也稱為整體-部分(Part-Whole)模式,屬于結構型模式。
它的宗旨是通過將單個對象(葉子節(jié)點)和組合對象(樹枝節(jié)點)用相同的接口進行表示,使得客戶端對單個對象和組合對象的使用具有一致性。
組合模式一般用來描述整體與部分的關系,它將對象組織到樹形結構中,最頂層的節(jié)點稱為根節(jié)點,根節(jié)點下面可以包含樹枝節(jié)點和葉子節(jié)點,樹枝節(jié)點下面又可以包含樹枝節(jié)點和葉子節(jié)點。
應用場景
1.希望客戶端可以忽略組合對象與單個對象的差異時。
2.對象層次具備整體和部分,呈樹形結構。
例如:樹形菜單,文件、文件夾的管理。
優(yōu)缺點
優(yōu)點:
1、高層模塊調用簡單。
2、節(jié)點自由增加。
缺點:
1.在使用組合模式時,其葉子和樹枝的聲明都是實現(xiàn)類,而不是接口,違反了依賴倒置原則。
主要角色
組合模式主要包含3個角色:
1.抽象根節(jié)點(Component)
定義系統(tǒng)各層次對象的共有方法和屬性,可以預先定義一些默認行為和屬性。
2.樹枝節(jié)點(Composite)
定義樹枝節(jié)點的行為,存儲子節(jié)點,組合樹枝節(jié)點和葉子節(jié)點形成一個樹形結構。
3.葉子節(jié)點(Laf)
葉子節(jié)點對象,其下再無分支,是系統(tǒng)層次遍歷的最小單位。
組合模式結構

分類
組合模式在具體實現(xiàn)上,有兩種不同的方式,分別是透明組合模式和安全組合模式。
透明組合模式將公共接口封裝到抽象根節(jié)點(Component)中,系統(tǒng)所有節(jié)點具備一致行為,如果當系統(tǒng)絕大多數層次具備相同的公共行為時,采用透明組合模式會更好。但是為剩下少數層次節(jié)點引入不需要的方法。
如果當系統(tǒng)各個層次差異性行為較多或者樹節(jié)點層次相對穩(wěn)定時,則采用安全組合模式。
透明組合模式
透明組合模式是把所有公共方法都定義在抽象根節(jié)點中,這樣做的好處是客戶端無需分辨是葉子節(jié)點(Leaf)和樹枝節(jié)點(Composite),它們具備完全一致的接口。缺點是葉子節(jié)點(Leaf)會繼承得到一些它所不需要(管理子類操作的方法)的方法,這與設計模式接口隔離原則相違背。
創(chuàng)建抽象根節(jié)點
把所有可能用到的方法都定義到這個最頂層的抽象類中,但是不寫任何邏輯處理的代碼,而是直接拋出異常。
禁止使用抽象方法,否則子類必須實現(xiàn),于是體現(xiàn)不出各個子類的差異。子類只需要重寫有差異的方法進行覆蓋即可。
舉例:分類目錄為根節(jié)點,具體分類為樹枝節(jié)點,分類下的商品為葉子節(jié)點。
public abstract class Component {
public String getName(Component component) {
throw new UnsupportedOperationException("getName is not supported");
}
public double getPrice(Component component) {
throw new UnsupportedOperationException("getPrice is not supported");
}
public String print() {
throw new UnsupportedOperationException("print is not supported");
}
public boolean addChild(Component component) {
throw new UnsupportedOperationException("addChild is not supported");
}
public boolean removeChild(Component component) {
throw new UnsupportedOperationException("removeChild is not supported");
}
public Component getChild(int index) {
throw new UnsupportedOperationException("getChild is not supported");
}
}創(chuàng)建樹枝節(jié)點
public class CompositeCategory extends Component {
private String name;
private List<Component> componentList = new ArrayList<Component>();
public CompositeCategory(String name) {
this.name = name;
}
@Override
public String print() {
StringBuilder builder = new StringBuilder(this.name);
for (Component component : this.componentList) {
if (component instanceof CompositeCategory) {
builder.append("\n" + "+-" + component.print());
} else {
builder.append("\n" + "+--" + component.print());
}
}
return builder.toString();
}
@Override
public boolean addChild(Component component) {
return this.componentList.add(component);
}
@Override
public boolean removeChild(Component component) {
return this.componentList.remove(component);
}
@Override
public Component getChild(int index) {
return this.componentList.get(index);
}
}創(chuàng)建葉子節(jié)點
public class CompositeProduct extends Component {
private String name;
private Double price;
public CompositeProduct(String name, Double price) {
this.name = name;
this.price = price;
}
@Override
public String print() {
return this.name + " (¥" + this.price + "元)";
}
@Override
public String getName(Component component) {
return this.name;
}
@Override
public double getPrice(Component component) {
return this.price;
}
}客戶端調用
public static void main(String[] args) {
// 根節(jié)點
Component root = new CompositeCategory("分類目錄");
// 樹枝節(jié)點
Component categoryA = new CompositeCategory("分類A");
Component categoryB = new CompositeCategory("分類B");
// 葉子節(jié)點
Component productA = new CompositeProduct("productA ", 20.5);
Component productB = new CompositeProduct("productB ", 30.5);
Component productC = new CompositeProduct("productC", 25.5);
root.addChild(categoryA);
categoryA.addChild(productA);
root.addChild(categoryB);
categoryB.addChild(productB);
categoryB.addChild(productC);
System.out.println(root.print());
System.out.println("-----------------------");
Component child = root.getChild(1);
System.out.println(child.print());
System.out.println("-----------------------");
root.removeChild(categoryA);
System.out.println(root.print());
}
分類目錄
+-分類A
+--productA (¥20.5元)
+-分類B
+--productB (¥30.5元)
+--productC (¥25.5元)
-----------------------
分類B
+--productB (¥30.5元)
+--productC (¥25.5元)
-----------------------
分類目錄
+-分類B
+--productB (¥30.5元)
+--productC (¥25.5元)
安全組合模式
安全組合模式是只規(guī)定系統(tǒng)各個層次的最基礎的一致行為,而把組合(樹節(jié)點)本身的方法(管理子類對象的添加,刪除等)放到自身當中。
安全組合模式的好處是接口定義職責清晰,符合設計模式單一職責原側和接口隔離原則;缺點是客戶需要區(qū)分樹枝節(jié)點(Composite)和葉子節(jié)點(Leaf),這樣才能正確處理各個層次的操作,客戶端無法依賴抽象(Component),違背了設計模式依賴倒置原則。
創(chuàng)建抽象根節(jié)點
public abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
public abstract String print();
}
創(chuàng)建樹枝節(jié)點
public class CompositeCategory extends Component {
private List<Component> componentList;
public CompositeCategory(String name) {
super(name);
this.componentList = new ArrayList<Component>();
}
@Override
public String print() {
StringBuilder builder = new StringBuilder(this.name);
for (Component component : this.componentList) {
if (component instanceof CompositeCategory) {
builder.append("\n" + "+-" + component.print());
} else {
builder.append("\n" + "+--" + component.print());
}
}
return builder.toString();
}
public boolean addChild(Component component) {
return this.componentList.add(component);
}
public boolean removeChild(Component component) {
return this.componentList.remove(component);
}
public Component getChild(int index) {
return this.componentList.get(index);
}
}創(chuàng)建葉子節(jié)點
public class CompositeProduct extends Component {
private Double price;
public CompositeProduct(String name, Double price) {
super(name);
this.price = price;
}
@Override
public String print() {
return this.name + " (¥" + this.price + "元)";
}
public String getName() {
return this.name;
}
public double getPrice() {
return this.price;
}
}客戶端調用
public static void main(String[] args) {
// 根節(jié)點
CompositeCategory root = new CompositeCategory("分類目錄");
// 樹枝節(jié)點
CompositeCategory categoryA = new CompositeCategory("分類A");
CompositeCategory categoryB = new CompositeCategory("分類B");
// 葉子節(jié)點
CompositeProduct productA = new CompositeProduct("productA", 20.5);
CompositeProduct productB = new CompositeProduct("productB", 30.5);
CompositeProduct productC = new CompositeProduct("productC", 25.5);
root.addChild(categoryA);
categoryA.addChild(productA);
root.addChild(categoryB);
categoryB.addChild(productB);
categoryB.addChild(productC);
System.out.println(root.print());
System.out.println("-----------------------");
Component child = root.getChild(1);
System.out.println(child.print());
System.out.println("-----------------------");
root.removeChild(categoryA);
System.out.println(root.print());
}分類目錄
+-分類A
+--productA (¥20.5元)
+-分類B
+--productB (¥30.5元)
+--productC (¥25.5元)
-----------------------
分類B
+--productB (¥30.5元)
+--productC (¥25.5元)
-----------------------
分類目錄
+-分類B
+--productB (¥30.5元)
+--productC (¥25.5元)
到此這篇關于Java結構型設計模式之組合模式詳解的文章就介紹到這了,更多相關Java組合模式內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java 實現(xiàn)簡單靜態(tài)資源Web服務器的示例
這篇文章主要介紹了Java 實現(xiàn)簡單靜態(tài)資源Web服務器的示例,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-11-11
Java利用StringBuffer替換特殊字符的方法實現(xiàn)
這篇文章主要介紹了Java利用StringBuffer替換特殊字符的方法實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-04-04
Mybatis傳入List實現(xiàn)批量更新的示例代碼
這篇文章主要介紹了Mybatis傳入List實現(xiàn)批量更新的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-10-10
基于Java實現(xiàn)動態(tài)切換ubuntu壁紙功能
這篇文章主要為大家詳細介紹了如何使用 Java 在 Ubuntu Linux 系統(tǒng)中實現(xiàn)自動切換壁紙的示例程序,感興趣的小伙伴可以跟隨小編一起學習一下2024-11-11

