在电脑磁盘里有文件和文件夹,文件夹里又可以放文件和文件夹,这个磁盘可以看做是一个树状结构,磁盘里的文件可以看做叶子,文件夹看做枝干。文件夹其实也是文件的一种形式,对它们可以进行相同的操作(复制、粘贴、删除)。
再来说说Android中的View和ViewGroup,ViewGroup是继承于View,因此ViewGroup和View可以同等看待。不同的是ViewGroup是一个容器,里面可以放View和ViewGroup,这是不是和上面文件的例子简直一毛一样。这就是组合模式。
定义:将对象组合成树形结构以表示“部分-整体”的层次结构,使用户对单个对象和组合对象的使用具有一致性。
结构:
- 组件:组合中的对象声明接口或抽象类,实现所有类共有接口的默认行为
- 叶子:叶子对象,组件的实现类。叶子结点没有子结点
- 容器:容器对象,组件的实现类,含有子节点,并实现了与子部件有关的操作
适用场景:
- 表示对象的“部分-整体”层次结构时
- 从一个整体中能够独立出部分模块或功能的场景
UML类图:
下面就是组合模式的代码实现,以文件和文件夹作为例子:
Component(组件):
//这里采用抽象类的方式
public abstract class File {
String name;
//增加这个方法,可以弥补违反依赖倒置原则的不足
//是否为文件夹
public abstract boolean isFolder();
public abstract void delete();
}
Composite(容器):
public class Folder extends File {
List<File> mList;
int mChildNumber;
public Folder(String name){
mList = new ArrayList<>();
this.name = name;
}
@Override
public boolean isFolder() {
//因为是文件夹,所以返回true
return true;
}
@Override
public void delete() {
//先删除子文件,再删除自身
for(int i=0;i<mChildNumber;i++){
File file = getFile(i);
file.delete();
}
System.out.println("删除了"+name+"文件夹");
}
public void addFile(File file){
mList.add(file);
mChildNumber++;
}
public void removeFile(File file){
mList.remove(file);
mChildNumber--;
}
public File getFile(int index){
return mList.get(index);
}
}
Leaf(叶子):
public class ImageFile extends File {
public ImageFile(String name){
this.name = name;
}
@Override
public boolean isFolder() {
return false;
}
@Override
public void delete() {
System.out.println("删除了"+name+"文件");
}
}
public class TextFile extends File {
public TextFile(String name){
this.name = name;
}
@Override
public boolean isFolder() {
return false;
}
@Override
public void delete() {
System.out.println("删除了"+name+"文件");
}
}
Test:
public class Test {
public static void main(String[] args){
Folder folder1 = new Folder("folder1");
ImageFile imageFile1 = new ImageFile("abc1.jpg");
ImageFile imageFile2 = new ImageFile("abc2.jpg");
TextFile textFile1 = new TextFile("abc1.txt");
TextFile textFile2 = new TextFile("abc2.txt");
Folder folder2 = new Folder("folder2");
folder2.addFile(textFile2);
folder2.addFile(imageFile2);
folder1.addFile(imageFile1);
folder1.addFile(textFile1);
folder1.addFile(folder2);
for(int i=0;i<folder1.mChildNumber;i++){
File file = folder1.getFile(i);
file.delete();
}
}
}
总结:组合对象的关键在于它定义了一个抽象构建类,它既可表示叶子对象,也可表示容器对象,客户仅仅需要针对这个抽象构建进行编程,无须知道他是叶子对象还是容器对象,都是一致对待(也提供了区分的方法isFolder)。组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构件也更容易;从上面代码也可以看出,基于这种树状结构的对象组合模式下,实现删除文件夹时的递归操作(先删除子文件,再删除自身)也是很轻松的。