<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          「補課」進行時:設計模式(14)——組合模式

          共 8397字,需瀏覽 17分鐘

           ·

          2020-11-24 16:05

          1. 前文匯總

          「補課」進行時:設計模式系列

          2. 某東的菜單

          前段時間雙十一,不知道各位的戰(zhàn)果如何,反正我是屯了兩盒口罩湊個數(shù)。

          電商平臺為我們提供的方便快捷的搜索框入口,我想大多數(shù)人在使用的時候應該都會使用這個入口,但其實電商平臺還為我們提供了另一個入口,就是它的分類體系,如下:

          我簡單抽象一下:

          -?服裝
          ????-?男裝
          ????????-?襯衣
          ????????-?夾克
          ????-?女裝
          ????????-?裙子
          ????????-?套裝

          可以看到,這是一個樹結構,在前端實現(xiàn)一個這種菜單樹可以選用 ZTree 插件,做過前端的都知道。

          下面,用 Java 代碼實現(xiàn)一下,輸出一下上面的這個樹狀結構:

          觀察這個樹狀結構,可以看到節(jié)點分為三種類型:

          • 根節(jié)點
          • 樹枝節(jié)點
          • 葉子節(jié)點(沒有子節(jié)點)

          根節(jié)點和樹枝節(jié)點的構造是比較類似的,都是可以有子節(jié)點,這兩個節(jié)點可以抽象成一個對象。

          首先定義一個葉子節(jié)點:

          public?class?Leaf?{
          ????//?葉子對象的名字
          ????private?String?name;
          ????//?構造方法
          ????public?Leaf(String?name)?{
          ????????this.name?=?name;
          ????}
          ????//?輸出葉子對象的結構,葉子對象沒有子對象,也就是輸出葉子對象的名字
          ????public?void?printStruct(String?preStr)?{
          ????????System.out.println(preStr?+?"?-?"?+?name);
          ????}
          }

          接著定義一個組合對象:

          public?class?Composite?{
          ????//?組合對象集合
          ????private?Collection?childComposite?=?new?ArrayList<>();
          ????//?葉子對象集合
          ????private?Collection?childLeaf?=?new?ArrayList<>();
          ????//?組合對象名稱
          ????private?String?name;
          ????//?構造函數(shù)
          ????public?Composite(String?name)?{
          ????????this.name?=?name;
          ????}
          ????//?向組合對象加入被它包含的其它組合對象
          ????public?void?addComposite(Composite?c){
          ????????this.childComposite.add(c);
          ????}
          ????//?向組合對象加入被它包含的葉子對象
          ????public?void?addLeaf(Leaf?leaf){
          ????????this.childLeaf.add(leaf);
          ????}
          ????//?輸出自身結構
          ????public?void?printStruct(String?preStr){
          ????????System.out.println(preStr?+?"?+?"?+?this.name);
          ????????preStr+="?";
          ????????for(Leaf?leaf?:?childLeaf){
          ????????????leaf.printStruct(preStr);
          ????????}
          ????????for(Composite?c?:?childComposite){
          ????????????c.printStruct(preStr);
          ????????}
          ????}
          }

          來一個測試類:

          public?class?Test?{
          ????public?static?void?main(String[]?args)?{
          ????????//定義所有的組合對象
          ????????Composite?root?=?new?Composite("服裝");
          ????????Composite?c1?=?new?Composite("男裝");
          ????????Composite?c2?=?new?Composite("女裝");

          ????????//定義所有的葉子對象
          ????????Leaf?leaf1?=?new?Leaf("襯衣");
          ????????Leaf?leaf2?=?new?Leaf("夾克");
          ????????Leaf?leaf3?=?new?Leaf("裙子");
          ????????Leaf?leaf4?=?new?Leaf("套裝");

          ????????//按照樹的結構來組合組合對象和葉子對象
          ????????root.addComposite(c1);
          ????????root.addComposite(c2);
          ????????c1.addLeaf(leaf1);
          ????????c1.addLeaf(leaf2);
          ????????c2.addLeaf(leaf3);
          ????????c2.addLeaf(leaf4);

          ????????//調(diào)用根對象的輸出功能來輸出整棵樹
          ????????root.printStruct("");
          ????}
          }

          上面的這種實現(xiàn)方案,雖然能實現(xiàn)了我們希望看到的功能,但是有一個很明顯的問題:那就是必須區(qū)分組合對象和葉子對象,并進行有區(qū)別的對待。

          3. 組合模式

          3.1 定義

          組合模式(Composite Pattern)也叫合成模式,有時又叫做部分-整體模式(Part-Whole),主要是用來描述部分與整體的關系,其定義如下:

          Compose objects into tree structures to represent part-wholehierarchies.Composite lets clients treat individual objects and compositionsof objects uniformly.(將對象組合成樹形結構以表示“部分-整體”的層次結構,使得用戶對單個對象和組合對象的使用具有一致性。)

          3.2 通用類圖

          • Component 抽象構件角色: 定義參加組合對象的共有方法和屬性,可以定義一些默認的行為或屬性。
          • Leaf 葉子構件: 葉子對象,其下再也沒有其他的分支,也就是遍歷的最小單位。
          • Composite 樹枝構件: 樹枝對象,它的作用是組合樹枝節(jié)點和葉子節(jié)點形成一個樹形結構。

          3.3 通用代碼

          public?abstract?class?Component?{
          ????//?整體和個體都共享的邏輯
          ????void?doSomething()?{
          ????????//?具體的業(yè)務邏輯
          ????}
          }

          public?class?Leaf?extends?Component?{
          ????//?可以復寫父類的方法
          ????@Override
          ????void?doSomething()?{
          ????????super.doSomething();
          ????}
          }

          public?class?Composite?extends?Component?{
          ????//?構建容器
          ????private?ArrayList?componentArrayList?=?new?ArrayList<>();
          ????//?增加一個葉子構件或者樹枝構件
          ????public?void?add(Component?component)?{
          ????????this.componentArrayList.add(component);
          ????}
          ????//?刪除一個葉子構件或者樹枝構件
          ????public?void?remove(Component?component)?{
          ????????this.componentArrayList.remove(component);
          ????}
          ????//?獲得分支下所有葉子構件或者樹枝構件

          ????public?ArrayList?getChildren()?{
          ????????return?this.componentArrayList;
          ????}
          }

          3.4 優(yōu)點

          1. 高層模塊調(diào)用簡單:

          一棵樹形機構中的所有節(jié)點都是 Component ,局部和整體對調(diào)用者來說沒有任何區(qū)別,也就是說,高層模塊不必關心自己處理的是單個對象還是整個組合結構,簡化了高層模塊的代碼。

          1. 節(jié)點自由增加:

          使用了組合模式后,我們可以看看,如果想增加一個樹枝節(jié)點、樹葉節(jié)點是不是都很容易,只要找到它的父節(jié)點就成,非常容易擴展,符合開閉原則,對以后的維護非常有利。

          4. 示例改進(安全模式)

          把最上面的示例修改成組合模式,首先需要定義一個抽象組件:

          public?abstract?class?Component?{
          ????//?輸出組件名稱
          ????abstract?void?printStruct(String?preStr);
          }

          葉子節(jié)點:

          public?class?Leaf?extends?Component?{

          ????private?String?name;

          ????public?Leaf(String?name)?{
          ????????this.name?=?name;
          ????}

          ????@Override
          ????void?printStruct(String?preStr)?{
          ????????System.out.println(preStr?+?"?-?"?+?name);
          ????}
          }

          樹枝節(jié)點:

          public?class?Composite?extends?Component{

          ????//?組合對象集合
          ????private?Collection?childComponents;

          ????//?組合對象的名字
          ????private?String?name;

          ????public?Composite(String?name)?{
          ????????this.name?=?name;
          ????}

          ????public?void?addChild(Component?child)?{
          ????????if?(this.childComponents?==?null)?{
          ????????????this.childComponents?=?new?ArrayList<>();
          ????????}
          ????????this.childComponents.add(child);
          ????}

          ????void?removeChild(Component?child)?{
          ????????this.childComponents.remove(child);
          ????}

          ????Collection?getChildren()?{
          ????????return?this.childComponents;
          ????}

          ????@Override
          ????void?printStruct(String?preStr)?{
          ????????System.out.println(preStr?+?"?+?"?+?this.name);
          ????????if?(this.childComponents?!=?null)?{
          ????????????preStr+="?";
          ????????????for(Component?c?:?this.childComponents){
          ????????????????//遞歸輸出每個子對象
          ????????????????c.printStruct(preStr);
          ????????????}
          ????????}
          ????}
          }

          測試類:

          public?class?Test?{
          ????public?static?void?main(String[]?args)?{
          ????????//?定義根節(jié)點
          ????????Composite?root?=?new?Composite("服裝");
          ????????//?創(chuàng)建兩個樹枝節(jié)點
          ????????Composite?c1?=?new?Composite("男裝");
          ????????Composite?c2?=?new?Composite("女裝");

          ????????//?定義所有的葉子對象
          ????????Leaf?leaf1?=?new?Leaf("襯衣");
          ????????Leaf?leaf2?=?new?Leaf("夾克");
          ????????Leaf?leaf3?=?new?Leaf("裙子");
          ????????Leaf?leaf4?=?new?Leaf("套裝");

          ????????//?按照樹的結構來組合組合對象和葉子對象
          ????????root.addChild(c1);
          ????????root.addChild(c2);
          ????????c1.addChild(leaf1);
          ????????c1.addChild(leaf2);
          ????????c2.addChild(leaf3);
          ????????c2.addChild(leaf4);
          ????????//?調(diào)用根對象的輸出功能來輸出整棵樹
          ????????root.printStruct("");
          ????}
          }

          5. 透明模式

          組合模式有兩種不同的實現(xiàn),安全模式和透明模式,上面的示例是安全模式,下面是透明模式的通用類圖:

          和上面的那個安全模式的通用類圖對比一下區(qū)別,就非常明顯了,只是單純的把幾個方法 addChild()removeChild()getChildren() 幾個方法放到了抽象類中。

          在透明模式中不管葉子對象還是樹枝對象都有相同的結構,通過判斷是否存在子節(jié)點來判斷葉子節(jié)點還是樹枝節(jié)點,如果處理不當,這個會在運行期出現(xiàn)問題。

          而在安全模式中,它是把樹枝節(jié)點和樹葉節(jié)點徹底分開,樹枝節(jié)點單獨擁有用來組合的方法,這種方案比較安全。

          抽象角色:

          public?abstract?class?Component?{
          ????//?輸出組件名稱
          ????abstract?void?printStruct(String?preStr);

          ????//?向組合對象中加入組件對象
          ????abstract?void?addChild(Component?child);

          ????//?從組合對象中移出某個組件對象
          ????abstract?void?removeChild(Component?child);

          ????//?返回組件對象
          ????abstract?Collection?getChildren();
          }

          葉子節(jié)點:

          public?class?Leaf?extends?Component?{

          ????private?String?name;

          ????public?Leaf(String?name)?{
          ????????this.name?=?name;
          ????}

          ????//?向組合對象中加入組件對象
          ????@Deprecated
          ????public?void?addChild(Component?child)?{
          ????????//?缺省實現(xiàn),如果子類未實現(xiàn)此功能,由父類拋出異常
          ????????throw?new?UnsupportedOperationException("對象不支持這個功能");
          ????}

          ????//?從組合對象中移出某個組件對象
          ????@Deprecated
          ????public?void?removeChild(Component?child){
          ????????//?缺省實現(xiàn),如果子類未實現(xiàn)此功能,由父類拋出異常
          ????????throw?new?UnsupportedOperationException("對象不支持這個功能");
          ????}

          ????@Deprecated
          ????Collection?getChildren()?{
          ????????throw?new?UnsupportedOperationException("對象不支持這個功能");
          ????}

          ????@Override
          ????void?printStruct(String?preStr)?{
          ????????System.out.println(preStr?+?"?-?"?+?name);
          ????}
          }

          這里使用 Deprecated 注解是為了在編譯期告訴調(diào)用者,這方法我有,可以調(diào)用,但是已經(jīng)失效了,如果一定要調(diào)用,那么在運行期會拋出 UnsupportedOperationException 的錯誤。

          樹枝節(jié)點:

          public?class?Composite?extends?Component?{

          ????//?組合對象集合
          ????private?Collection?childComponents;

          ????//?組合對象的名字
          ????private?String?name;

          ????public?Composite(String?name)?{
          ????????this.name?=?name;
          ????}

          ????public?void?addChild(Component?child)?{
          ????????if?(this.childComponents?==?null)?{
          ????????????this.childComponents?=?new?ArrayList<>();
          ????????}
          ????????this.childComponents.add(child);
          ????}

          ????@Override
          ????void?removeChild(Component?child)?{
          ????????this.childComponents.remove(child);
          ????}

          ????@Override
          ????Collection?getChildren()?{
          ????????return?this.childComponents;
          ????}

          ????@Override
          ????void?printStruct(String?preStr)?{
          ????????System.out.println(preStr?+?"?+?"?+?this.name);
          ????????if?(this.childComponents?!=?null)?{
          ????????????preStr+="?";
          ????????????for(Component?c?:?this.childComponents){
          ????????????????//遞歸輸出每個子對象
          ????????????????c.printStruct(preStr);
          ????????????}
          ????????}
          ????}
          }

          測試類:

          public?class?Test?{
          ????public?static?void?main(String[]?args)?{
          ????????//定義所有的組合對象
          ????????Component?root?=?new?Composite("服裝");
          ????????Component?c1?=?new?Composite("男裝");
          ????????Component?c2?=?new?Composite("女裝");

          ????????//定義所有的葉子對象
          ????????Component?leaf1?=?new?Leaf("襯衣");
          ????????Component?leaf2?=?new?Leaf("夾克");
          ????????Component?leaf3?=?new?Leaf("裙子");
          ????????Component?leaf4?=?new?Leaf("套裝");

          ????????//按照樹的結構來組合組合對象和葉子對象
          ????????root.addChild(c1);
          ????????root.addChild(c2);
          ????????c1.addChild(leaf1);
          ????????c1.addChild(leaf2);
          ????????c2.addChild(leaf3);
          ????????c2.addChild(leaf4);
          ????????//調(diào)用根對象的輸出功能來輸出整棵樹
          ????????root.printStruct("");
          ????}
          }

          6. 參考

          https://www.jianshu.com/p/dead42334033





          感謝閱讀



          瀏覽 50
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91精品国产91久久久久久久久久 | 激情自拍偷拍 | 亚洲免费免费在线观看 | 亚洲视频免费视频在线视频免费视频 | 国产乱伦小说视频 |