瞭解23種設計模式之組合模式

一,什麼是組合模式

 Composite 模式 也叫組合模式,是構造型的設計模式之一,通過遞歸手段來構造樹形的對象結構,並可以通過一個對象來訪問整個對象樹

二,組合模式的結構

組合模式的角色和職責

Component : (樹形結構的節點抽象)   

  • 爲所有的對象定義統一的接口,(公共屬性,行爲等的定義)
  • 提供管理子節點對象的接口方法
  • (選擇)提供管理父節點對象的接口方法

Leaf : (樹形結構的葉節點)

Composite: (樹形結構的枝節點) 

優點:

  1. 組合模式使得客戶端代碼可以一致地處理單個對象和組合對象,無須關心自己處理的是單個對象,還是組合對象,這簡化了客戶端代碼;
  2. 更容易在組合體內加入新的對象,客戶端不會因爲加入了新的對象而更改源代碼,滿足“開閉原則”;

缺點:

  1. 設計較複雜,客戶端需要花更多時間理清類之間的層次關係;
  2. 不容易限制容器中的構件;
  3. 不容易用繼承的方法來增加構件的新功能;

組合模式分爲透明式的組合模式和安全式的組合模式。

 

四:透明方式代碼實現:

透明方式:在該方式中,由於抽象構件聲明瞭所有子類中的全部方法,所以客戶端無須區別樹葉對象和樹枝對象,對客戶端來說是透明的。但其缺點是:樹葉構件本來沒有 Add()、Remove() 及 GetChild() 方法,卻要實現它們(空實現或拋異常),這樣會帶來一些安全性問題。

Component

public interface IFile {

    /**
     * @Description: 顯示文件夾的名稱
     * @param:
     * @return: void
     **/
    public void display();

    /**
     * @Description: 添加
     * @param: []
     * @return: boolean
     **/
    public boolean add(IFile iFile);

    /**
     * @Description: 刪除
     * @param: []
     * @return: boolean
     **/
    public boolean remove(IFile iFile);

    /**
     * @Description: 獲得子節點
     * @param: []
     * @return: java.util.List<com.enjoy.cap26.IFile>
     **/
    public List<IFile> getChildren();
 }

Leaf

/**
 * @ClassName Files
 * @Description TODO
 * @Version 1.0
 **/
public class Files implements IFile{

    private String name;

    public Files(String name) {
        this.name = name;
    }

    @Override
    public void display() {
        System.out.println(name);
    }

    @Override
    public boolean add(IFile iFile) {
        return false;
    }

    @Override
    public boolean remove(IFile iFile) {
        return false;
    }

    @Override
    public List<IFile> getChildren() {
        return null;
    }
}

 Composite

/**
 * @ClassName Folder
 * @Description TODO
 * @Version 1.0
 **/
public class Folder implements IFile{

    private String name;
    private List<IFile> children;

    public Folder(String name) {
        this.name = name;
        children = new ArrayList<IFile>();
    }

    @Override
    public void display() {
        System.out.println(name);
    }

    @Override
    public boolean add(IFile iFile) {

        return children.add(iFile);
    }

    @Override
    public boolean remove(IFile iFile) {

        return  children.remove(iFile);
    }

    @Override
    public List<IFile> getChildren() {
        return children;
    }
}

測試:

/**
 * @ClassName test
 * @Description TODO
 * @Version 1.0
 **/
public class Test {

    public static void main(String[] args) {
          //父節點
          Folder folder = new Folder("D:");

          //子節點 目錄
          Folder javaFoder = new Folder("java");

          //子節點 helloworld.txt
          Files  files = new Files("helloworld.txt");

          folder.add(javaFoder);
          folder.add(files);

          Folder sprFoder = new Folder("spring");
          Files files2 = new Files("springAop-api");
          javaFoder.add(sprFoder);
          javaFoder.add(files2);

          //子節點 目錄
          Folder stuFoder = new Folder("學習");
          Files files1 = new Files("String.txt");

          folder.add(stuFoder);
          folder.add(files1);


          displayTree(folder,0);

    }

    /**
     * 使用遞歸
     * @param iFile
     * @param deep
     */
    public static  void  displayTree(IFile iFile,int deep){
        for (int i = 0; i < deep;i++){
            System.out.print("--");
        }
        //顯示自身名稱
        iFile.display();

        List<IFile>  children = iFile.getChildren();

        for (IFile file : children) {
            if( file instanceof Files){
                for (int i = 0; i <= deep;i++){
                    System.out.print("---");
                }
                file.display();
            }else{
                displayTree(file,deep+1);
            }
        }

    }

}

五,安全方式

安全方式:在該方式中,將管理子構件的方法移到樹枝構件中,抽象構件和樹葉構件沒有對子對象的管理方法,這樣就避免了上一種方式的安全性問題,但由於葉子和分支有不同的接口,客戶端在調用時要知道樹葉對象和樹枝對象的存在,所以失去了透明性。

 Component 

/**
 * @ClassName Articles
 * @Description 抽象構建
 * @Version 1.0
 **/
public interface Articles {

    /**
     * @Description: 計算
     * @param: []
     * @return: float
     * @Author: wuchao
     * @Date: 2020/6/26 20:31
     **/
    public float calculation();


    /**
     * @Description: 顯示
     * @param: []
     * @return: void
     * @Author: wuchao
     * @Date: 2020/6/26 20:32
     **/
    public  void show();
}

leaf: 

/**
 * @ClassName Goods
 * @Description 樹葉構件
 * @Version 1.0
 **/
public class Goods implements  Articles{

    private String name;

    /**
     * 數量
     */
    private int quantity;

    /**
     * 單價
     */
    private float unitPrice;


    public Goods(String name, int quantity, float unitPrice) {
        this.name = name;
        this.quantity = quantity;
        this.unitPrice = unitPrice;
    }

    @Override
    public float calculation() {
        return quantity*unitPrice;
    }

    @Override
    public void show() {
        System.out.println(name+"(數量:"+quantity+",單價:"+unitPrice+"元)");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }

    public float getUnitPrice() {
        return unitPrice;
    }

    public void setUnitPrice(float unitPrice) {
        this.unitPrice = unitPrice;
    }
}

 

Composite 

/**
 * @ClassName Bags
 * @Description TODO
 * @Version 1.0
 **/
public class Bags implements Articles{

    private String name;
    private List<Articles> list;


    public Bags(String name) {
        this.name = name;
        list = new ArrayList<Articles>();
    }

    @Override
    public float calculation() {
        float s=0;
        for(Object obj:list)
        {
            s+=((Articles)obj).calculation();
        }
        return s;
    }

    @Override
    public void show() {
        for(Object obj:list) {
            ((Articles)obj).show();
        }
    }


    /**
     * 新增對象
     * @param c
     */
    public void add(Articles c) {
        list.add(c);
    }

    /**
     * 刪除對象
     * @param c
     */
    public void remove(Articles c) {
        list.remove(c);
    }

    /**
     * 獲得list
     * @return
     */
    public List<Articles> getChild(){
        return list;
    }
}

 

 

測試:

public class Test {

    public static void main(String[] args) {
        float s=0;
        Bags BigBag,mediumBag,smallRedBag,smallWhiteBag;
        Goods sp;
        BigBag=new Bags("大袋子");
        mediumBag=new Bags("中袋子");
        smallRedBag=new Bags("紅色小袋子");
        smallWhiteBag=new Bags("白色小袋子");
        sp=new Goods("婺源特產",2,7.9f);
        smallRedBag.add(sp);
        sp=new Goods("婺源地圖",1,9.9f);
        smallRedBag.add(sp);
        sp=new Goods("韶關香菇",2,68);
        smallWhiteBag.add(sp);
        sp=new Goods("韶關紅茶",3,180);
        smallWhiteBag.add(sp);
        sp=new Goods("景德鎮瓷器",1,380);
        mediumBag.add(sp);
        mediumBag.add(smallRedBag);
        sp=new Goods("李寧牌運動鞋",1,198);
        BigBag.add(sp);
        BigBag.add(smallWhiteBag);
        BigBag.add(mediumBag);
        System.out.println("您選購的商品有:");
        BigBag.show();
        s=BigBag.calculation();
        System.out.println("要支付的總價是:"+s+"元");
    }
}

  

六,組合模式的應用場景

  1. 在需要表示一個對象整體與部分的層次結構的場合。
  2. 要求對用戶隱藏組合對象與單個對象的不同,用戶可以用統一的接口使用組合結構中的所有對象的場合。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章