<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Java設計模式學習記錄-組合模式

      前言

      今天要介紹的設計模式是組合模式,組合模式也是結構型設計模式的一種,它主要體現了整體與部分的關系,其典型的應用就是樹形結構。組合是一組對象,其中的對象可能包含一個其他對象,也可能包含一組其他對象。

      組合模式

      組合模式定義為:將對象組合成樹形結構以表示“整體-部分”的層次結構。組合模式是單個對象和組合對象的使用具有一致性。

      在使用組合模式的使用要注意以下兩點:

      組合中既要能包含個體,也要能包含其他組合。

      要抽象出對象和組合的公共特性。

      舉例說明

      介紹了一些基本內容,可能會還是不清楚組合模式到底是什么樣的一個模式,還是老樣子,舉??說明。

      在我們的家用PC電腦上的文件結構就是一個很好的例子,例如在我的電腦上有如下圖所示的文件目錄結構。

      從root文件夾到具體的文件,一層一層的這種結構就是典型的樹形結構,root是硬盤中的某個文件夾,可以理解為根節點,這個文件下下面有兩個文件夾和一個文件,image-folder文件夾這種有分支的可以理解為分支節點,文件則理解為葉子節點

      為了要實現這種結構,這三種節點,我們一般的思路是,創建三個根節點、分支節點、葉子節點這三個類,但是我們發現根節點的特性其實和分支節點一樣,可以理解為一類,所以我們只需要創建兩個類就可以。

      定義分支節點(包含根節點)的接口

      /**
       * 定義分支節點(根節點)
       */
      public interface IBranch {
      
          /**
           * 獲得分支節點信息
           * @return
           */
          public String getInfo();
      
          /**
           * 增加分支節點(文件夾下還可能會有文件夾)
           * @param branch
           */
          public void addBranch(IBranch branch);
      
          /**
           * 增加葉子節點
           * @param leaf
           */
          public void addLeaf(ILeaf leaf);
      
          /**
           * 獲得子集
           * @return
           */
          public ArrayList getChildren();
      }

      具體的實現如下

      /**
       * 分支節點(文件夾)
       */
      public class Folder implements IBranch{
      
          /**
           * 節點名稱
           */
          private String name;
      
          /**
           * 子集
           */
          private ArrayList children = Lists.newArrayList();
      
          /**
           * 帶參數的構造方法
           * @param name
           */
          public Folder(String name){
              this.name = name;
          }
      
          /**
           * 獲得分支節點信息
           *
           * @return
           */
          @Override
          public String getInfo() {
      
              return "名稱:" + name;
          }
      
          /**
           * 增加分支節點(文件夾下還可能會有文件夾)
           *
           * @param branch
           */
          @Override
          public void addBranch(IBranch branch) {
      
              children.add(branch);
          }
      
          /**
           * 增加葉子節點
           *
           * @param leaf
           */
          @Override
          public void addLeaf(ILeaf leaf) {
              children.add(leaf);
          }
      
          /**
           * 獲得子集
           *
           * @return
           */
          @Override
          public ArrayList getChildren() {
              return children;
          }
      }

      定義葉子節點的接口

      /**
       * 定義葉子節點
       */
      public interface ILeaf {
      
          /**
           * 獲得葉子節點的信息
           * @return
           */
          public String getInfo();
      
      }

      因為葉子節點,不會有子集所以只需要一個獲得描述信息的方法即可,具體的實現如下。

      /**
       * 葉子節點(文件)
       */
      public class File implements ILeaf {
      
          private String name;
      
          /**
           *
           * @param name
           */
          public File(String name){
              this.name = name;
          }
      
          /**
           * 獲得葉子節點的信息
           *
           * @return
           */
          @Override
          public String getInfo() {
              return "名稱:"+name;
          }
      }

      節點類已經定義完成了,所以現在可以開始組裝數據了,然后將最終的數據打印出來看看是不是這個結構。

      public class ClientTest {
      
          public static void main(String[] args) {
      
              //定義根節點
              IBranch root = new Folder("root");
      
              //定義二級節點的文件夾
              IBranch imageFolder = new Folder("image-folder");
              IBranch documentFolder = new Folder("document-folder");
              //定義二級節點的文件
              ILeaf systemFile = new File("system-file.bat");
      
              //定義三級節點的文件夾
              IBranch pngFolder = new Folder("png-folder");
              IBranch gifFolder = new Folder("gif-folder");
              //定義三級節點的文件
              ILeaf testHtml = new File("test.html");
              ILeaf testJS = new File("test.js");
      
              //定義四級節點的文件,兩個png文件
              ILeaf test1png = new File("test1.png");
              ILeaf test2png = new File("test2.png");
              //定義四級節點的文件3個gif文件
              ILeaf my1gif = new File("my1.gif");
              ILeaf my2gif = new File("my2.gif");
              ILeaf my3gif = new File("my3.gif");
      
              //填充一級文件夾
              root.addBranch(imageFolder);
              root.addBranch(documentFolder);
              root.addLeaf(systemFile);
              //填充二級圖片文件夾
              imageFolder.addBranch(pngFolder);
              imageFolder.addBranch(gifFolder);
              //填充二級文檔文件夾
              documentFolder.addLeaf(testHtml);
              documentFolder.addLeaf(testJS);
      
              //填充三級png圖片文件夾
              pngFolder.addLeaf(test1png);
              pngFolder.addLeaf(test2png);
              //填充三級gif圖片文件夾
              gifFolder.addLeaf(my1gif);
              gifFolder.addLeaf(my2gif);
              gifFolder.addLeaf(my3gif);
      
              System.out.println(root.getInfo());
      
              //打印出來
              getChildrenInfo(root.getChildren());
      
          }
      
          /**
           * 遞歸遍歷文件
           * @param arrayList
           */
          private static void getChildrenInfo(ArrayList arrayList){
      
              int length = arrayList.size();
      
              for(int m = 0;m<length;m++){
                  Object item = arrayList.get(m);
                  //如果是葉子節點就直接打印出來名稱
                  if(item instanceof ILeaf){
                      System.out.println(((ILeaf) item).getInfo());
                  }else {
                      //如果是分支節點就先打印分支節點的名稱,再遞歸遍歷子節點
                      System.out.println(((IBranch)item).getInfo());
                      getChildrenInfo(((IBranch)item).getChildren());
                  }
      
              }
      
          }
      
      }

      最終的打印結果:

      名稱:root
      名稱:image-folder
      名稱:png-folder
      名稱:test1.png
      名稱:test2.png
      名稱:gif-folder
      名稱:my1.gif
      名稱:my2.gif
      名稱:my3.gif
      名稱:document-folder
      名稱:test.html
      名稱:test.js
      名稱:system-file.bat

       這個結果確實是我們想要的,但是仔細看看其實還是有可以優化的地方,Folder和File都有包含名字的構造方法,以及getInfo()方法,那么是不是可以抽取出來?那就改變一下吧。

      新增節點公共抽象類

      /**
       * 節點公共抽象類
       */
      public abstract class Node {
      
          private String name;
      
          /**
           * 帶參數的構造方法
           * @param name
           */
          public Node(String name){
              this.name = name;
          }
      
          /**
           * 獲得節點信息
           * @return
           */
          public String getInfo(){
              return "名稱:"+name;
          }
      }

      改造后的File類

      /**
       * 葉子節點(文件)
       */
      public class File extends Node {
          
          /**
           * 調用父類的構造方法
           * @param name
           */
          public File(String name) {
              super(name);
          }
      }

      改造后的Folder類

      /**
       * 分支節點(文件夾)
       */
      public class Folder extends Node{
      
          /**
           * 子集
           */
          private ArrayList children = Lists.newArrayList();
      
          /**
           * 帶參數的構造方法
           * @param name
           */
          public Folder(String name){
              super(name);
          }
      
          /**
           * 新增節點,有可能是文件也有可能是文件夾
           * @param node
           */
          public void add(Node node){
              this.children.add(node);
          }
      
          /**
           * 獲得子集
           *
           * @return
           */
          public ArrayList getChildren() {
              return children;
          }
      }

      改造后的使用方式

      public class ClientTest {
      
          public static void main(String[] args) {
      
              //定義根節點
              Folder root = new Folder("root");
      
              //定義二級節點的文件夾
              Folder imageFolder = new Folder("image-folder");
              Folder documentFolder = new Folder("document-folder");
              //定義二級節點的文件
              File systemFile = new File("system-file.bat");
      
              //定義三級節點的文件夾
              Folder pngFolder = new Folder("png-folder");
              Folder gifFolder = new Folder("gif-folder");
              //定義三級節點的文件
              File testHtml = new File("test.html");
              File testJS = new File("test.js");
      
              //定義四級節點的文件,兩個png文件
              File test1png = new File("test1.png");
              File test2png = new File("test2.png");
              //定義四級節點的文件3個gif文件
              File my1gif = new File("my1.gif");
              File my2gif = new File("my2.gif");
              File my3gif = new File("my3.gif");
      
              //填充一級文件夾
              root.add(imageFolder);
              root.add(documentFolder);
              root.add(systemFile);
              //填充二級圖片文件夾
              imageFolder.add(pngFolder);
              imageFolder.add(gifFolder);
              //填充二級文檔文件夾
              documentFolder.add(testHtml);
              documentFolder.add(testJS);
      
              //填充三級png圖片文件夾
              pngFolder.add(test1png);
              pngFolder.add(test2png);
              //填充三級gif圖片文件夾
              gifFolder.add(my1gif);
              gifFolder.add(my2gif);
              gifFolder.add(my3gif);
      
              System.out.println(root.getInfo());
      
              //打印出來
              getChildrenInfo(root.getChildren());
      
          }
      
          /**
           * 遞歸遍歷文件
           * @param arrayList
           */
          private static void getChildrenInfo(ArrayList arrayList){
      
              int length = arrayList.size();
      
              for(int m = 0;m<length;m++){
                  Object item = arrayList.get(m);
                  //如果是葉子節點就直接打印出來名稱
                  if(item instanceof File){
                      System.out.println(((File) item).getInfo());
                  }else {
                      //如果是分支節點就先打印分支節點的名稱,再遞歸遍歷子節點
                      System.out.println(((Folder)item).getInfo());
                      getChildrenInfo(((Folder)item).getChildren());
                  }
      
              }
      
          }
      
      }

      這樣實現起來的各個節點的代碼變的更簡潔了,但是組裝數據的的代碼是沒變的。因為放數據要么自己造要么從某個地方查詢出來,這么個步驟是不能簡化的。

      分析

      現在我們的這個實現過程就是使用的了組合模式,下面我們來分析一下組合模式都有哪些部分組成。先來看一下根據上面這個例子畫出來的類圖。

      組合模式主要有這么幾個角色:

      抽象構件角色

      (Node類)這是一個抽象角色,它給參加組合的對象規定一個接口或抽象類,給出組合中對象的默認行為。

      葉子構件角色

      (File類)代表參加組合的葉子節點對象,沒有子集,并且要定義出參加組合的原始對象行為。

      樹枝構件角色

      (Folder類)代表參加組合的含義子對象的對象,并且也要給出參加組合的原始對象行為以及遍歷子集的行為。

      組合模式的兩種形式

      透明方式

      透明方式來實現組合模式是指,按照上面舉得例子來說,File和Folder的方法和和屬性都一樣,就是說File也包含children屬性和getChildren方法兩者在類上沒有什么區別,只不過File的children為null,getChildren()獲得的也永遠是空。這樣葉子節點對象和樹枝節點對象的區別在抽象層次上就消失了,客戶端可以同等對待所有對象。

      這種方式的缺點是不夠安全,因為葉子節點和樹枝節點在本質上是有區別的,葉子節點的getChildren()方法和children的存在沒有意義,雖然在編譯時不會出錯,但是如果在運行時之前沒有做過處理是很容易拋出異常的。

      安全方式(非透明)

      安全方式實現的組合模式,就是上面的例子介紹的那樣,這種實現方式把葉子和樹枝徹底的區分開來處理,并做到互不干擾,樹枝有單獨自己處理子類的方法,保證運行期不會出錯。

      一般在如下情況下應當考慮使用組合模式:

      1. 需要描述對象的部分和整體的等級結構。
      2. 需要客戶端忽略掉個體構件和組合構件的區別,客戶端平等對待所以構件。

      其實在我們日常的業務當中有很多場景其實都是可以使用組合模式的,例如,某公司的人員組織結構,從CEO到小職員,一級一級的人員關系就可以使用組合模式,還有就是在網上商城購物時,選擇地址,從省道區再到縣也是可以使用組合模式的。

       

       

       

       

       

       

       

       

       

      想了解更多的設計模式請查看Java設計模式學習記錄-GoF設計模式概述

       

      posted @ 2018-07-27 14:32  紀莫  閱讀(730)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产永久免费高清在线观看| 九九视频热最新在线视频| 国产精品黄色一区二区三区| 色婷婷婷丁香亚洲综合| 中文字幕亚洲制服在线看| 国产av熟女一区二区三区| 国产不卡一区二区在线| 少妇人妻偷人精品视频| 999国产精品999久久久久久 | 亚洲AV无码秘?蜜桃蘑菇| 九九久久精品国产免费看小说 | 最新国产精品精品视频| 3d全彩无码啪啪本子全彩| 国产成人精品视频不卡| 国产成人片无码视频在线观看| 久久午夜私人影院| 国产一区二区三区精品综合 | 少妇午夜啪爽嗷嗷叫视频| 亚洲欧美日韩在线码| 中文字幕国产精品资源| 性久久久久久| 亚洲日韩国产一区二区三区在线| 高清中文字幕国产精品| 亚洲日本欧洲二区精品| 强奷乱码中文字幕| 丁香五月激情图片| 成人无码午夜在线观看| 性色在线视频精品| 无遮无挡爽爽免费视频| 色综合久久久久综合体桃花网| 麻豆精品一区二区三区蜜臀| 国内精品久久久久影院日本| 中文字幕精品无码一区二区| 国产在线视频精品视频| 国产精品大全中文字幕| 国产女人喷潮视频免费| 九九热久久这里全是精品| 国产桃色在线成免费视频| 亚洲日本中文字幕天天更新| 在线a级毛片无码免费真人| 天天躁日日摸久久久精品|