為了讓系統(tǒng)具有更好的靈活性和可擴(kuò)展性,客戶端可以一致地對待文件和文件夾,Sunny 公司開發(fā)人員使用組合模式來進(jìn)行殺毒軟件的框架設(shè)計,其基本結(jié)構(gòu)如圖所示:
http://wiki.jikexueyuan.com/project/design-pattern-structurized/images/1347030143_6150.jpg" alt="殺毒軟件框架設(shè)計結(jié)構(gòu)圖" />
在圖中, AbstractFile 充當(dāng)抽象構(gòu)件類,F(xiàn)older 充當(dāng)容器構(gòu)件類,ImageFile、TextFile 和 VideoFile 充當(dāng)葉子構(gòu)件類。完整代碼如下所示:
import java.util.*;
//抽象文件類:抽象構(gòu)件
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();
}
//圖像文件類:葉子構(gòu)件
class ImageFile extends AbstractFile {
private String name;
public ImageFile(String name) {
this.name = name;
}
public void add(AbstractFile file) {
System.out.println("對不起,不支持該方法!");
}
public void remove(AbstractFile file) {
System.out.println("對不起,不支持該方法!");
}
public AbstractFile getChild(int i) {
System.out.println("對不起,不支持該方法!");
return null;
}
public void killVirus() {
//模擬殺毒
System.out.println("----對圖像文件'" + name + "'進(jìn)行殺毒");
}
}
//文本文件類:葉子構(gòu)件
class TextFile extends AbstractFile {
private String name;
public TextFile(String name) {
this.name = name;
}
public void add(AbstractFile file) {
System.out.println("對不起,不支持該方法!");
}
public void remove(AbstractFile file) {
System.out.println("對不起,不支持該方法!");
}
public AbstractFile getChild(int i) {
System.out.println("對不起,不支持該方法!");
return null;
}
public void killVirus() {
//模擬殺毒
System.out.println("----對文本文件'" + name + "'進(jìn)行殺毒");
}
}
//視頻文件類:葉子構(gòu)件
class VideoFile extends AbstractFile {
private String name;
public VideoFile(String name) {
this.name = name;
}
public void add(AbstractFile file) {
System.out.println("對不起,不支持該方法!");
}
public void remove(AbstractFile file) {
System.out.println("對不起,不支持該方法!");
}
public AbstractFile getChild(int i) {
System.out.println("對不起,不支持該方法!");
return null;
}
public void killVirus() {
//模擬殺毒
System.out.println("----對視頻文件'" + name + "'進(jìn)行殺毒");
}
}
//文件夾類:容器構(gòu)件
class Folder extends AbstractFile {
//定義集合fileList,用于存儲AbstractFile類型的成員
private ArrayList<AbstractFile> fileList=new ArrayList<AbstractFile>();
private String name;
public Folder(String name) {
this.name = name;
}
public void add(AbstractFile file) {
fileList.add(file);
}
public void remove(AbstractFile file) {
fileList.remove(file);
}
public AbstractFile getChild(int i) {
return (AbstractFile)fileList.get(i);
}
public void killVirus() {
System.out.println("****對文件夾'" + name + "'進(jìn)行殺毒"); //模擬殺毒
//遞歸調(diào)用成員構(gòu)件的killVirus()方法
for(Object obj : fileList) {
((AbstractFile)obj).killVirus();
}
}
}
編寫如下客戶端測試代碼:
class Client {
public static void main(String args[]) {
//針對抽象構(gòu)件編程
AbstractFile file1,file2,file3,file4,file5,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 TextFile("九陰真經(jīng).txt");
file4 = new TextFile("葵花寶典.doc");
file5 = new VideoFile("笑傲江湖.rmvb");
folder2.add(file1);
folder2.add(file2);
folder3.add(file3);
folder3.add(file4);
folder4.add(file5);
folder1.add(folder2);
folder1.add(folder3);
folder1.add(folder4);
//從“Sunny的資料”節(jié)點開始進(jìn)行殺毒操作
folder1.killVirus();
}
}
編譯并運(yùn)行程序,輸出結(jié)果如下:
****對文件夾'Sunny的資料'進(jìn)行殺毒
****對文件夾'圖像文件'進(jìn)行殺毒
----對圖像文件'小龍女.jpg'進(jìn)行殺毒
----對圖像文件'張無忌.gif'進(jìn)行殺毒
****對文件夾'文本文件'進(jìn)行殺毒
----對文本文件'九陰真經(jīng).txt'進(jìn)行殺毒
----對文本文件'葵花寶典.doc'進(jìn)行殺毒
****對文件夾'視頻文件'進(jìn)行殺毒
----對視頻文件'笑傲江湖.rmvb'進(jìn)行殺毒
由于在本實例中使用了組合模式,在抽象構(gòu)件類中聲明了所有方法,包括用于管理和訪問子構(gòu)件的方法,如 add() 方法和 remove() 方法等,因此在 ImageFile 等葉子構(gòu)件類中實現(xiàn)這些方法時必須進(jìn)行相應(yīng)的異常處理或錯誤提示。在容器構(gòu)件類 Folder 的 killVirus() 方法中將遞歸調(diào)用其成員對象的 killVirus() 方法,從而實現(xiàn)對整個樹形結(jié)構(gòu)的遍歷。
如果需要更換操作節(jié)點,例如只需對文件夾“文本文件”進(jìn)行殺毒,客戶端代碼只需修改一行即可,將代碼:
folder1.killVirus();
改為:
folder3.killVirus();
輸出結(jié)果如下:
****對文件夾'文本文件'進(jìn)行殺毒
----對文本文件'九陰真經(jīng).txt'進(jìn)行殺毒
----對文本文件'葵花寶典.doc'進(jìn)行殺毒
在具體實現(xiàn)時,我們可以創(chuàng)建圖形化界面讓用戶選擇所需操作的根節(jié)點,無須修改源代碼,符合“開閉原則”,客戶端無須關(guān)心節(jié)點的層次結(jié)構(gòu),可以對所選節(jié)點進(jìn)行統(tǒng)一處理,提高系統(tǒng)的靈活性。