
原文地址:LoveDev
對于樹形結構,容器對象(如文件夾)可以進行添加刪除葉子對象(如文件)等操作,但是葉子對象就不能具備這樣的操作,所以容器對象和葉子對象需要區別對待,但是這樣會使得程序非常復雜,通常我們希望可以一致的處理它們,組合模式就是為此類問題而誕生,組合模式通過一種巧妙的設計方案使得用戶可以一致性地處理整個樹形結構或者樹形結構的一部分,也可以一致性地處理樹形結構中的葉子對象和容器對象
組合模式(Composite Pattern):組合多個對象形成樹形結構以表示具有“整體-部分”關系的層次結構,組合模式又可以稱為“整體-部分”(Part-Whole)模式,是一種結構型模式

透明組合模式
- Component(抽象構件):可以是接口或者抽象類,為葉子對象和容器對象聲明接口
- Leaf(葉子對象):對于增加、刪除等操作,可以通過異常進行處理,只實現屬于葉子對象的方法
- Composite(容器對象):包含葉子對象的容器
先來用透明組合模式實現一個獲取文件后綴名的操作:
Component 類:
public abstract class AbstractFile {
private String name;
public AbstractFile(String name) {
this.name = name;
}
public abstract void addFile(AbstractFile file);
public abstract void removeFile(AbstractFile file);
public abstract AbstractFile getFile(int index);
public abstract void getFileSuffix();
}
Leaf 類:
// Java 文件對象
public class JavaFile extends AbstractFile {
public JavaFile(String name) {
super(name);
}
@Override
public void addFile(AbstractFile file) {
throw new UnsupportedOperationException("不支持操作");
}
@Override
public void removeFile(AbstractFile file) {
throw new UnsupportedOperationException("不支持操作");
}
@Override
public AbstractFile getFile(int index) {
throw new UnsupportedOperationException("不支持操作");
}
@Override
public void getFileSuffix() {
LogUtils.i("Java 文件的后綴名是 .java");
}
}
// text 文件對象
public class TextFile extends AbstractFile {
public TextFile(String name) {
super(name);
}
@Override
public void addFile(AbstractFile file) {
throw new UnsupportedOperationException("不支持操作");
}
@Override
public void removeFile(AbstractFile file) {
throw new UnsupportedOperationException("不支持操作");
}
@Override
public AbstractFile getFile(int index) {
throw new UnsupportedOperationException("不支持操作");
}
@Override
public void getFileSuffix() {
LogUtils.i("Text 文件的后綴名是 .txt");
}
}
Composite 類:
public class Folder extends AbstractFile {
ArrayList<AbstractFile> fileList = new ArrayList<>();
public Folder(String name) {
super(name);
}
@Override
public void addFile(AbstractFile file) {
fileList.add(file);
}
@Override
public void removeFile(AbstractFile file) {
fileList.remove(file);
}
@Override
public AbstractFile getFile(int index) {
return fileList.get(index);
}
@Override
public void getFileSuffix() {
LogUtils.i("文件夾無后綴名");
for (AbstractFile abstractFile : fileList) {
abstractFile.getFileSuffix();
}
}
}
Client 類:
AbstractFile text1 = new TextFile("text1");
AbstractFile text2 = new TextFile("text2");
AbstractFile javaFile1 = new JavaFile("javaFile1");
AbstractFile javaFile2 = new JavaFile("javaFile2");
AbstractFile folder1 = new Folder("folder1");
AbstractFile folder2 = new Folder("folder2");
AbstractFile folder3 = new Folder("folder3");
folder1.addFile(text1);
folder1.addFile(javaFile1);
folder2.addFile(text2);
folder2.addFile(javaFile2);
folder3.addFile(folder1);
folder3.addFile(folder2);
folder3.getFileSuffix();
如果僅僅是獲取文件后綴名,暫時沒有任何問題,但是不熟悉代碼得小伙伴調用了 TextFile
中的 addFile()
函數,又沒有進行異常處理,就會導致程序出現異常,這就是透明組合模式的缺點,對于調用者來說所有函數足夠透明,但是一不小心就會導致程序出現異常
下面再來介紹另外一種組合模式,叫做安全組合模式:

安全組合模式
利用該模式再實現一下上面獲取文件后綴名的操作:
Component 類:
public abstract class AbstractSafeFile {
private String name;
public AbstractSafeFile(String name) {
this.name = name;
}
public abstract void getFileSuffix();
}
Leaf 類:
// Java 文件對象
public class JavaFile extends AbstractSafeFile {
public JavaFile(String name) {
super(name);
}
@Override
public void getFileSuffix() {
LogUtils.i("Java 文件的后綴名是 .java");
}
}
// text 文件對象
public class TextFile extends AbstractSafeFile {
public TextFile(String name) {
super(name);
}
@Override
public void getFileSuffix() {
LogUtils.i("Text 文件的后綴名是 .txt");
}
}
Composite 類:
public class Folder extends AbstractSafeFile {
ArrayList<AbstractFile> fileList = new ArrayList<>();
public Folder(String name) {
super(name);
}
@Override
public void addFile(AbstractFile file) {
fileList.add(file);
}
@Override
public void removeFile(AbstractFile file) {
fileList.remove(file);
}
@Override
public AbstractFile getFile(int index) {
return fileList.get(index);
}
@Override
public void getFileSuffix() {
LogUtils.i("文件夾無后綴名");
for (AbstractFile abstractFile : fileList) {
abstractFile.getFileSuffix();
}
}
}
Client 類:
TextFile text1 = new TextFile("text1");
TextFile text2 = new TextFile("text2");
JavaFile javaFile1 = new JavaFile("javaFile1");
JavaFile javaFile2 = new JavaFile("javaFile2");
Folder folder1 = new Folder("folder1");
Folder folder2 = new Folder("folder2");
Folder folder3 = new Folder("folder3");
folder1.addFile(text1);
folder1.addFile(javaFile1);
folder2.addFile(text2);
folder2.addFile(javaFile2);
folder3.addFile(folder1);
folder3.addFile(folder2);
folder3.getFileSuffix();
安全組合模式中的 Component 類不提供任何管理成員對象的方法,在 Composite 類中自己實現這些方法,這種做法雖然安全了,但是不能針對抽象編程,不夠透明,要有區別的對待葉子對象和容器對象,正所謂魚與熊掌不可兼得