Android設計模式(十八)-組合模式

組合模式,也稱作部分整體模式。是結構型設計模式之一。組合模式畫成圖就是數據結構中的樹結構,有一個根節點,然后有很多分支。將最頂部的根節點叫做根結構件,將有分支的節點叫做枝干構件,將沒有分支的末端節點叫做葉子構件.

博客地址

定義

將對象組合成樹形結構以表示“部分-整體”的層次結構,使得用戶對單個對象和組合對象的使用具有一致性。

使用場景

  • 想表示對象的部分-整體層次結構時。
  • 希望用戶忽略單個對象和組合對象的不同,對對象使用具有統一性時。
  • 從一個整體中能夠獨立出部分模塊或功能時。

UML

安全的組合模式

  • Component:抽象節點,為組合中的對象聲明接口,適當的時候實現所有類的公有接口方法的默認行為。
  • Composite:定義所有枝干節點的行為,存儲子節點,實現相關操作。
  • Leaf:葉子節點,沒有子節點,實現相關對象的行為。

看一下這個模式的通用代碼

抽象的節點:

public abstract class Component {
    protected String name;

    public Component(String name) {
        this.name = name;
    }
    public abstract void doSonthing();
}

枝干節點:

public class Composite extends Component {
    private List<Component> components = new ArrayList<>();
    public Composite(String name) {
        super(name);
    }

    @Override
    public void doSonthing() {
        System.out.println(name);
        if (null!=components){
            for (Component c:components) {
                c.doSonthing();
            }
        }
    }

    public void addChild(Component child){
        components.add(child);
    }
    public void removeChild(Component child){
        components.remove(child);
    }
    public Component getChild(int index){
        return components.get(index);
    }

}

葉子節點:

public class Leaf extends Component {
    public Leaf(String name) {
        super(name);
    }

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

客戶端調用:

public class CLient {
    public static void main(String[] args) {
        Composite root = new Composite("root");
        Composite branch1 = new Composite("branch1");
        Composite branch2 = new Composite("branch2");
        Composite branch3 = new Composite("branch3");

        Leaf leaf1 = new Leaf("leaf1");
        Leaf leaf2 = new Leaf("leaf2");
        Leaf leaf3 = new Leaf("leaf3");

        branch1.addChild(leaf1);
        branch3.addChild(leaf2);
        branch3.addChild(leaf3);

        root.addChild(branch1);
        root.addChild(branch2);
        root.addChild(branch3);

        root.doSonthing();
    }
}

輸出:


我們可以發現在Client使用的時候,根本沒用到接口Component。違反了依賴倒置原則。

因為接口中沒有定義公共方法,必須使用對應搞得實現節點才能完成相應的操作,叫安全的組合模式。

透明的組合模式

所以就有一種透明的組合模式,所有的節點都包含有同樣的結構

抽象的節點:

public abstract class Component {
    protected String name;

    public Component(String name) {
        this.name = name;
    }
    public abstract void doSonthing();

    public abstract void addChild(Component child);
    public abstract void removeChild(Component child);
    public abstract Component getChild(int index);
}

枝干節點:

public class Composite extends Component {
    private List<Component> components = new ArrayList<>();
    public Composite(String name) {
        super(name);
    }

    @Override
    public void doSonthing() {
        System.out.println(name);
        if (null!=components){
            for (Component c:components) {
                c.doSonthing();
            }
        }
    }

    public void addChild(Component child){
        components.add(child);
    }
    public void removeChild(Component child){
        components.remove(child);
    }
    public Component getChild(int index){
        return components.get(index);
    }

}

葉子節點:

public class Leaf extends Component {
    public Leaf(String name) {
        super(name);
    }

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

    @Override
    public void addChild(Component child) {
        throw new UnsupportedOperationException("葉子節點沒有子節點");
    }

    @Override
    public void removeChild(Component child) {
        throw new UnsupportedOperationException("葉子節點沒有子節點");
    }

    @Override
    public Component getChild(int index) {
        throw new UnsupportedOperationException("葉子節點沒有子節點");
    }
}

客戶端調用:

public class CLient {
    public static void main(String[] args) {
        Component root = new Composite("root");
        Component branch1 = new Composite("branch1");
        Component branch2 = new Composite("branch2");
        Component branch3 = new Composite("branch3");

        Component leaf1 = new Leaf("leaf1");
        Component leaf2 = new Leaf("leaf2");
        Component leaf3 = new Leaf("leaf3");

        branch1.addChild(leaf1);
        branch3.addChild(leaf2);
        branch3.addChild(leaf3);

        root.addChild(branch1);
        root.addChild(branch2);
        root.addChild(branch3);

        root.doSonthing();
    }
}

輸出:


簡單實現

以文件夾系統舉個例子:

抽象的文件系統:

public abstract class Dir {
    protected List<Dir> dirs = new ArrayList<>();
    private String name;

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

    public abstract void addDir(Dir dir);
    public abstract void rmDir(Dir dir);//刪除文件或文件夾
    public abstract void clear();//清空所有元素
    public abstract void print();//打印文件夾系統結構
    public abstract List<Dir> getFiles();
    public  String getName(){
        return name;
    }
}

文件夾:

public class Folder extends Dir {
    public Folder(String name) {
        super(name);
    }

    @Override
    public void addDir(Dir dir) {
        dirs.add(dir);
    }

    @Override
    public void rmDir(Dir dir) {
        dirs.remove(dir);
    }

    @Override
    public void clear() {
        dirs.clear();
    }

    @Override
    public void print() {
        //利用遞歸來輸出文件夾結構
        System.out.print(getName()+"(");
        Iterator<Dir> i = dirs.iterator();
        while (i.hasNext()){
            Dir dir = i.next();
            dir.print();
            if (i.hasNext()){
                System.out.print(", ");
            }
        }
        System.out.print(")");
    }

    @Override
    public List<Dir> getFiles() {
        return dirs;
    }
}

文件:

public class File extends Dir {
    public File(String name) {
        super(name);
    }

    @Override
    public void addDir(Dir dir) {
        throw new UnsupportedOperationException("文件不支持此操作");
    }

    @Override
    public void rmDir(Dir dir) {
        throw new UnsupportedOperationException("文件不支持此操作");
    }

    @Override
    public void clear() {
        throw new UnsupportedOperationException("文件不支持此操作");
    }

    @Override
    public void print() {
        System.out.print(getName());
    }

    @Override
    public List<Dir> getFiles() {
        throw new UnsupportedOperationException("文件不支持此操作");
    }
}

客戶端調用:

public class Client {
    public static void main(String[] args) {
        //創建根目錄 root
        Dir root = new Folder("root");
        //root下有個文件log.txt和三個文件夾 system,user,lib;
        root.addDir(new File("log.txt"));
        Dir system = new Folder("system");
        system.addDir(new File("systemlog.txt"));
        root.addDir(system);
        Dir user = new Folder("user");
        user.addDir(new File("usernamelist.txt"));
        root.addDir(user);
        Dir lib = new Folder("lib");
        lib.addDir(new File("libs.txt"));
        root.addDir(lib);
        root.print();
    }
}

輸出:

Android源碼中的組合模式

組合模式在Android中太常用了,View和ViewGroup就是一種很標準的組合模式:

在Android的視圖樹中,容器一定是ViewGroup,只有ViewGroup才能包含其他View和ViewGroup。View是沒有容器的。者是一種安全的組合模式。

總結

在Android開發中用到組合模式并不很多,組合模式更多的用于界面UI的架構設計上,而這部分讓開發者去實現的并不多。

優點

  • 可以清楚定義分層次的復雜對象,表示全部或部分層次,讓高層忽略層次的差異,方便對整個層次結構進行控制。
  • 高層模塊可以一致的使用一個組合結構或其中的單個對象,不必掛心處理的是單個對象還是整個組合結構,簡化了高層模塊的代碼。
  • 增加新的枝干和葉子構件都很方便,無需對現有類進行任何修改,就像增加一個自定義View一樣。
  • 將對象之間的關系形成樹形結構,便于控制。

缺點

  • 設計變得更加抽象,因此很難限制組合中的組件,因為他們都來自相同的抽象層。所以必須在運行時進行類型檢查才能實現。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 設計模式匯總 一、基礎知識 1. 設計模式概述 定義:設計模式(Design Pattern)是一套被反復使用、多...
    MinoyJet閱讀 3,978評論 1 15
  • 目錄 本文的結構如下: 引言 什么是組合模式 模式的結構 典型代碼 代碼示例 優點和缺點 適用環境 模式應用 一、...
    w1992wishes閱讀 915評論 0 2
  • 1 場景問題# 1.1 商品類別樹## 考慮這樣一個實際的應用:管理商品類別樹。 在實現跟商品有關的應用系統的時候...
    七寸知架構閱讀 6,073評論 10 59
  • 介紹 組合模式(Composite Pattern) 也稱為部分-整體模式(Part-Whole Pattern)...
    任教主來也閱讀 271評論 0 0
  • 1.組合模式的定義及使用場景組合模式也稱為部分整體模式,結構型設計模式之一,組合模式比較簡單,它將一組相似的對象看...
    GB_speak閱讀 873評論 0 2