1. 程式人生 > >設計模式的藝術 結構性模式之組合模式

設計模式的藝術 結構性模式之組合模式

不懂使用為學過,說出用途,繪製結構為了解,不會靈活使用基本等於沒學。

前言

樹形結構在軟體中隨處可見,比如系統中的目錄結構,應用軟體中的選單,如何運用面向物件的方式來處理這種樹形結構是組合模式需要解決的問題。組合模式通過一種巧妙的設計方案來使得使用者可以一致性的處理整個樹形結構或者樹形結構的一部分,也可以一致的處理樹形結構中的葉子節點。

什麼是組合模式  Composite Pattern

組合多個物件形成樹形結構以表示具有"整體-部門"關係的層次結構。組合模式對單個物件(葉子物件)和組合物件(容器物件)的使用具有一致性,所有又被稱之為"整體-部分"模式,它是一種結構性模式

組合模式的優點

(1)、可以清楚的定義分層次的複雜物件,表示物件的全部或部分層次,她讓客戶端忽略了層次的差異,方便對於整個層次結構進行控制

(2)、客戶端可以一致的使用一個組合結構或其中單個物件,不必關心處理的是單個物件還是整體組合結構,簡化了客戶端程式碼

(3)、組合模式中增加了新的容器構件和葉子構件都很方便,無須對現有類庫進行任何修改,符合開閉原則

(4)、組合模式為樹形結構的面向物件實現提供了一種靈活的解決方案,通過葉子物件和容器物件的遞迴組合,可以形成複雜的樹形結構,但對樹形結構的控制卻非常簡單。

組合模式的缺點

在增加新構件時很難對容器中的構件型別進行限制。有時候希望一個容器中只能有某些特定型別的物件,例如在某個資料夾中只能包含文字檔案,使用組合模式時,不能依賴型別系統來施加這些約束,因為它們都來自於相同的抽象層,在這種情況下,必須通過在執行時進行型別檢查來實現,這個實現過程就比較複雜

組合模式的使用場景

(1)、具有整體和部分的層次結構中,希望通過一種方式忽略整體與部分的差異,客戶端可以一致的對待它們。

(2)、在一個使用面嚮物件語言開發的系統中需要處理一個樹形結構。

(3)、在一個系統中能夠分離出葉子物件和容器物件,而且它們的型別不固定,需要增加一些新的型別。

組合模式的具體實現

專案結構

抽象構件

package com.company;

//抽象檔案類:抽象構件
public abstract class AbstractFile {
        public abstract void add(AbstractFile file);
        public abstract void remove(AbstractFile file);
        public abstract AbstractFile getChild(int i);
        public abstract void killVirus();
}

容器構件

package com.company;

import java.util.ArrayList;

//資料夾類:容器構件
public class Folder extends AbstractFile {
    //定義集合fileList,用於儲存AbstractFile型別的成員
    private ArrayList<AbstractFile> fileList=new ArrayList<AbstractFile>();
    private String name;

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

    @Override
    public void add(AbstractFile file) {
        fileList.add(file);
    }

    @Override
    public void remove(AbstractFile file) {
        fileList.remove(file);
    }

    @Override
    public AbstractFile getChild(int i) {

        return (AbstractFile) fileList.get(i);
    }

    @Override
    public void killVirus() {
        System.out.println("********對資料夾*********"+name+"進行防毒");  //模擬防毒
        //遞迴呼叫成員構件的killVirus()方法
        for(Object obj:fileList){
            ((AbstractFile)obj).killVirus();
    }
}

        }

葉子構件

package com.company.file;

import com.company.AbstractFile;

//影象檔案類:葉子構件
public class ImageFile extends AbstractFile {
    private String name;

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

    @Override
    public void add(AbstractFile file) {
        System.out.println("對不起,不支援該方法!");
    }

    @Override
    public void remove(AbstractFile file) {
        System.out.println("對不起,不支援該方法!");
    }

    @Override
    public AbstractFile getChild(int i) {
        System.out.println("對不起,不支援該方法!");
        return null;
    }

    @Override
    public void killVirus() {
        //模擬防毒
        System.out.println("-------對影象檔案-----------"+name+"進行防毒");

    }
}
package com.company.file;

import com.company.AbstractFile;

public class TextFile extends AbstractFile {
    private String name;

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

    @Override
    public void add(AbstractFile file) {
        System.out.println("對不起,不支援該方法!");
    }

    @Override
    public void remove(AbstractFile file) {
        System.out.println("對不起,不支援該方法!");
    }

    @Override
    public AbstractFile getChild(int i) {
        System.out.println("對不起,不支援該方法!");
        return null;
    }

    @Override
    public void killVirus() {
        //模擬防毒
        System.out.println("-------對文字檔案-----------"+name+"進行防毒");
    }
}

測試類

package com.company;

import com.company.file.ImageFile;

public class Client {

    public static void main(String[] args) {
   // write your code here
        //針對抽象構件程式設計
        AbstractFile file1,file2,file3,file4,folder1,folder2,folder3,folder4;
        folder1=new Folder("Sunny的資料");
        folder2=new Folder("影象檔案");
        folder3=new Folder("文字檔案");
        folder4=new Folder("視訊檔案");

        file1=new ImageFile("小龍女.jpg");
        file2=new ImageFile("張無忌.gif");
        file3=new ImageFile("九陰真經.txt");
        file4=new ImageFile("葵花寶典.doc");

        folder1.add(file1);
        folder2.add(file2);
        folder3.add(file3);
        folder4.add(file4);
        //從"Sunny的資料"節點開始進行防毒
        folder1.killVirus();
        folder2.killVirus();
        folder3.killVirus();
        folder4.killVirus();
    }
}

轉載請註明出處,掌聲送給社會人