java 設計模式:組合模式

1、概念

將對象以樹形結構組織起來,以達成“部分-整體”的層次機構,使得客戶端對單個對象和組合對象的使用具有一致性。

是用於把一組相似的對象當作一個單一的對象。組合模式依據樹形結構來組合對象,用來表示部分以及整體層次。這種類型的設計模式屬於結構型模式,它創建了對象組的樹形結構。

這種模式創建了一個包含自己對象組的類。該類提供了修改相同對象組的方式。

2、使用場景

部分、整體場景,如樹形菜單,文件、文件夾的管理。

  1. 需要表示一個對象整體或部分層次
  2. 希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。

3、如何使用

樹枝和葉子實現統一接口,樹枝內部組合該接口。

4、UML結構圖分析

5、實際代碼分析

例:文件與文件夾的關係

先進行普通的實現方式

//文件類
public class File {
    public String name;

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

    /**
     * 操作方法
     * @return
     */
    public String getName() {
        return name;
    }

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

    public void watch() {
        System.out.println("文件名"+getName()+"文件數目");
    }
}
//文件夾類
public class Folder{
    public String name;

    private List<File> mFileList;
    public Folder(String name) {
        mFileList = new ArrayList<>();
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    public void watch() {
        StringBuilder sb = new StringBuilder();
        for(File f:mFileList){
            sb.append(f.name);
        }
        System.out.println("文件名"+getName()+"文件數目"+ mFileList.size()+"名字"+sb.toString());
    }

    public void add(File file) {
        mFileList.add(file);
    }

    public void remove(File file) {
        mFileList.remove(file);
    }

    public File getChild(int pos) {
        return mFileList.get(pos);
    }
}
//運行
        File file = new File("hehe");
        Folder folder = new Folder("heere");
        folder.add(file);
        folder.watch();

文件和文件夾作爲兩個類來進行操作,將文件類進行添加文件,但是呢?如果文件夾下添加文件夾該咋辦呢?就需要再創建一個list來存放文件夾,這樣大家都是節點,爲啥搞得這麼複雜呢?既然存在上下級節點的問題,咱們就抽象爲一個抽象類,用抽象類作爲節點,子類就是文件夾和文件。

//將文件與文件夾統一看作是一類節點,做一個抽象類來定義這種節點,然後以其實現類來區分文件與目錄,在實現類中分別定義各自的具體實現內容,把組合方法寫到這個節點類中
public abstract class File {

    public String name;

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

    /**
     * 操作方法
     * @return
     */
    public String getName() {
        return name;
    }

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

    public abstract void watch();

    /**
     * 組合方法
     * @param file
     */
    public void add(File file){
        throw new UnsupportedOperationException();
    }

    public void remove(File file){
        throw new UnsupportedOperationException();
    }

    public File getChild(int pos){
        throw new UnsupportedOperationException();
    }

}
public class Folder extends File{

    private List<File> mFileList;
    public Folder(String name) {
        super(name);
        mFileList = new ArrayList<>();
    }

    @Override
    public void watch() {
        StringBuilder sb = new StringBuilder();
        for(File f:mFileList){
            sb.append(f.name);
        }
        System.out.println("文件名"+getName()+"文件數目"+ mFileList.size()+"名字"+sb.toString());
    }

    @Override
    public void add(File file) {
        mFileList.add(file);
    }

    @Override
    public void remove(File file) {
        mFileList.remove(file);
    }

    @Override
    public File getChild(int pos) {
        return mFileList.get(pos);
    }
}
public class TestFile extends File {
    public TestFile(String name) {
        super(name);
    }

    @Override
    public void watch() {
        System.out.println("文件名"+getName()+"文件數目");
    }
}
//運行
        TestFile file = new TestFile("hehe");
        Folder folder = new Folder("heere");
        folder.add(file);
        folder.watch();
        folder.getChild(0).watch();

這種組合模式正是應樹形結構而生,所以組合模式的使用場景就是出現樹形結構的地方。比如:文件目錄顯示,多及目錄呈現等樹形結構數據的操作。

安全組合模式(簡化)如下code

//將文件與文件夾統一看作是一類節點,做一個抽象類來定義這種節點,然後以其實現類來區分文件與目錄,在實現類中分別定義各自的具體實現內容,把組合方法寫到這個節點類中
public abstract class File {

    public String name;

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

    /**
     * 操作方法
     * @return
     */
    public String getName() {
        return name;
    }

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

    public abstract void watch();


}
public class Folder extends File{

    private List<File> mFileList;
    public Folder(String name) {
        super(name);
        mFileList = new ArrayList<>();
    }

    @Override
    public void watch() {
        StringBuilder sb = new StringBuilder();
        for(File f:mFileList){
            sb.append(f.name);
        }
        System.out.println("文件名"+getName()+"文件數目"+ mFileList.size()+"名字"+sb.toString());
    }

    public void add(File file) {
        mFileList.add(file);
    }

    public void remove(File file) {
        mFileList.remove(file);
    }

    public File getChild(int pos) {
        return mFileList.get(pos);
    }
}
public class TestFile extends File {
    public TestFile(String name) {
        super(name);
    }

    @Override
    public void watch() {
        System.out.println("文件名"+getName()+"文件數目");
    }
}
//運行
        TestFile file = new TestFile("hehe");
        Folder folder = new Folder("heere");
        folder.add(file);
        folder.watch();
        folder.getChild(0).watch();

安全組合模式分工就很明確了。它還有一個好處就是當我們add/remove的時候,我們能知道具體的類是什麼了,而透明組合模式就得在運行時去判斷,比較麻煩。

優點:

  1. 高層模塊調用簡單
  2. 節點自由增加

缺點:

  1. 在使用組合模式時,其葉子和樹枝的聲明都是實現類,而不是接口,違反了依賴倒置原則。
  2. 葉子類型不能控制。比如我想控制ViewGroup添加的View必須爲TextView的時候,約束起來就很麻煩。特別是類型多的時候。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章