设计模式:组合模式(Composite)
歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。
歡迎跳轉到本文的原文鏈接:https://honeypps.com/design_pattern/composite/
將對象組合成屬性結構以表示“部分-整體”的層次結構。組合使得用戶和單個對象和組合對象的使用具有一致性。
組合模式設計的角色:
舉個簡單例子(樹枝和葉子)
1 Component
2 Leaf(樹葉)
public class Leaf extends Component {public Leaf(String name){super(name);}@Deprecatedpublic void add(Component component) throws UnsupportedOperationException{throw new UnsupportedOperationException();}@Deprecatedpublic void remove(Component component) throws UnsupportedOperationException{throw new UnsupportedOperationException();}@Overrideprotected void operation(int depth){String temp = "";for(int i=0;i<depth;i++){temp += " ";}System.out.println(temp+this.name);}@Deprecatedprotected List<Component> getChildren() throws UnsupportedOperationException{throw new UnsupportedOperationException();} }3 Composite(樹枝)
public class Composite extends Component {private LinkedList<Component> children;public Composite(String name){super(name);this.children = new LinkedList<>();}public void add(Component component){this.children.add(component);}@Overridepublic void remove(Component component){this.children.remove(component);}@Overridepublic LinkedList<Component> getChildren(){return children;}@Overrideprotected void operation(int depth){String temp = "";for(int i=0;i<depth;i++){temp += " ";}LinkedList<Component> children = this.getChildren();System.out.println(temp+this.name);for (Component c : children) {c.operation(depth+1);}} }4 測試代碼
public class MainTest {public static void main(String[] args){Composite root = new Composite("樹根");Composite branch01 = new Composite("樹枝01");Composite branch02 = new Composite("樹枝02");Composite branch03 = new Composite("樹枝03");Composite branch04 = new Composite("樹枝04");branch01.add(new Leaf("樹葉01"));branch01.add(new Leaf("樹葉02"));branch03.add(new Leaf("樹葉03"));branch03.add(new Leaf("樹葉04"));branch03.add(new Leaf("樹葉05"));branch01.add(branch03);branch02.add(new Leaf("樹葉06"));branch02.add(new Leaf("樹葉07"));branch02.add(new Leaf("樹葉08"));branch04.add(new Leaf("樹葉09"));branch04.add(new Leaf("樹葉10"));branch02.add(branch04);root.add(branch01);root.add(branch02);root.operation(0);} }輸出結果:
樹根樹枝01樹葉01樹葉02樹枝03樹葉03樹葉04樹葉05樹枝02樹葉06樹葉07樹葉08樹枝04樹葉09樹葉10上面測試代碼部分構建樹結構的代碼著實不太好看,效率太低。其實,在真實應用中。并不是這樣子手工地構建一棵復雜的樹,應該是我們已經將整棵樹的節點內容、邏輯關系都存儲在數據庫表中,開發人員編程從數據庫中的表中讀取記錄來構建整棵樹。
透明模式 vs 安全模式
上面的代碼屬于透明模式,我們先看看安全模式是怎么實現的:
更改一下Component:
再更改下Leaf
public class Leaf extends Component {public Leaf(String name){super(name);}@Overrideprotected void operation(int depth){String temp = "";for(int i=0;i<depth;i++){temp += " ";}System.out.println(temp+this.name);} }被稱為安全模式是因為Leaf不具有add和remove等方法,這些具體方法是被下置到Composite類中去具體實現了。透明模式將add和remove等方法上升到抽象構建類Component中去了。那么此時Leaf類在具體實現時就必須將繼承而來的add和remove等不可用、不合理的方法給注釋掉(@Deprecated),并拋出適當的異常,不提供給用戶使用。至于是使用透明模式還是安全模式就仁者見仁智者見智咯。不過,在這一模式中,相對于安全性,我們比較強調透明性。
使用場景:
優缺點
優點:使客戶端調用簡單,客戶端可以一直的使用組合結構或其中單個對象,用戶就不必關心自己處理的是單個對象還是整個組合結構,這就簡化了客戶端代碼。更容易在組合體內加入對象不見,客戶端不必因為加入了新的對象不見而更改代碼。這一點符合開閉原則的要求,對系統的二次開發和功能擴展很有利。
缺點:組合模式不容易限制組合中的構件。
Jdk中的組合模式
java.util.Map#putAll(Map)
java.util.List#addAll(Collection)
java.util.Set#addAll(Collection)
反面教材
?回想起以前寫頁面菜單的時候,從數據庫中讀取類似的樹形結構,當時沒有采用這種組合模式,而是限定死樹的最大深度(頁面的菜單深度不超過3,實際上也沒見到過超過3的),這樣前端js代碼在深度不超過3時沒有問題,當超過3時,就需要重新編寫頁面菜單的js代碼了,這樣的擴展性并不好,如果當時采用了這種組合模式就會好很多。
?寫頁面菜單已經是6年前的事了,代碼早已不詳~最近用項目需求要寫一棵樹,單例模式的。大伙來看看有什么不妥之處。
首先定義實體類Entry
public class Entry {private String name;//some other propertiespublic Entry(String name){super();this.name = name;}//getter and setter略 }定義樹節點(這里的葉子節點可以看成son==null的TreeNode,而樹枝節點son!=null)
public class TreeNode {private Entry entry;private List<TreeNode> son;//getter and setter略 }定義單例樹節點
public class Tree {private TreeNode tree;private Tree(){tree = new TreeNode();tree.setEntry(null);tree.setSon(new ArrayList<TreeNode>());}public static class SingletonTreeInner{public static final Tree INSTANCE = new Tree();}public static Tree getInstance(){return SingletonTreeInner.INSTANCE;}public TreeNode getTree(){return tree;} }測試代碼(根-集群-主機-虛擬機的層次關系):
public static void insertData(){Tree root = Tree.getInstance();List<TreeNode> rootList = root.getTree().getSon();//add cluster into root nodeTreeNode cluster = new TreeNode();Entry entry1 = new Entry("cluster1");cluster.setEntry(entry1);cluster.setSon(null);rootList.add(cluster);//add host into cluster nodeTreeNode host = new TreeNode();Entry entry2 = new Entry("host1");host.setEntry(entry2);host.setSon(null);if(cluster.getSon() == null){cluster.setSon(new ArrayList<TreeNode>());}List clusterList = cluster.getSon();clusterList.add(host);//add vm into host nodeTreeNode vm = new TreeNode();Entry entry3 = new Entry("vm1");vm.setEntry(entry3);vm.setSon(null);if(host.getSon() == null){host.setSon(new ArrayList<TreeNode>());}List hostList = host.getSon();hostList.add(vm);}大伙比對組合模式來看看這段代碼有什么欠妥之處,歡迎在下方留言探討。
參考資料
歡迎跳轉到本文的原文鏈接:https://honeypps.com/design_pattern/composite/
歡迎支持筆者新作:《深入理解Kafka:核心設計與實踐原理》和《RabbitMQ實戰指南》,同時歡迎關注筆者的微信公眾號:朱小廝的博客。
總結
以上是生活随笔為你收集整理的设计模式:组合模式(Composite)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设计模式:原型模式(Prototype)
- 下一篇: 设计模式:享元模式(Flyweight)