我们平时在Android开发的过程中组合模式的应用并不多,组合模式更适合用于对一些界面ui的架构设计上,因此真正需要开发者去实现的不多。
- 优点
组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让高层模块忽略了层次的差异,方便对整个层次结构进行控制。
高层模块可以一致地使用一个组合结构或其中单个对象,不必关心处理地是单个对象还是整个组合结构,简化了高层模块地代码。
在组合结构中新增地枝干构件和叶子构件都很方便,无须对现有类库进行任何修改,符合“开闭原则”。
组合模式为树形结构地面向对象实现提供了一种灵活地解决方案,通过叶子对象和枝干对象地递归组合,可以形成复杂地树形结构,但对树形结构地控制却非常简单。 - 缺点
在新增构件时不好对枝干中地构件类型进行限制,不能依赖类型系统来施加这些约束,因为在大多数情况下,它们都是来自于抽象层,此时,必须进行类型检查来实现,这个实现过程较为复杂。
说了这么多理论,现在我们亲自动手实现一个组合模式的案例。
import java.util.ArrayList;
import java.util.List;
public abstract class Dir {
//声明一个list存储文件夹下的所有元素
protected List<Dir> dirs = new ArrayList<Dir>();
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;
}
}
import java.util.Iterator;
import java.util.List;
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> iter = dirs.iterator();
while (iter.hasNext()) {
Dir dir = iter.next();
dir.print();
if (iter.hasNext()) {
System.out.print(", ");
}
}
System.out.print(")");
}
@Override
public List<Dir> getFiles() {
return dirs;
}
}
import java.util.List;
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) {
Dir disk = new Folder("C");
disk.addDir(new File("aaa.txt"));
Dir dirWin = new Folder("Windowx");
dirWin.addDir(new File("xxx.txt"));
disk.addDir(dirWin);
disk.print();
}
}
上面的案例就是一个典型的组合模式的写法,组合模式的核心个人认为是在于最开始的抽象类(即Dir类)的设计上,Folder和File只是继承了该抽象类进行不同的方法实现而已,在使用时使用多态的方法进行初始化。因此,采用组合模式进行代码设计时必须考虑好抽象方法,不然后面不是很好扩展。
组合模式在Android源码中的实现
在Android源码中有一处便使用到了组合模式——view和viewgroup的嵌套组合。有读过这部分代码的同学就会知道Android源码中的组合模式并不是像上面案例一样让viewgroup和view分别实现某个抽象类,他是让viewgroup继承view,然后将viewgroup特有的功能定义在viewparent和viewmanager这两个接口中。
需要注意的是viewgroup是抽象类。其将view中的onlayout方法重置为抽象方法,也就是说容器子类必须实现该方法来实现布局定位,我们知道对于view类该方法是一个空实现,因为对于一个普通的view来说该方法并没有什么实现价值,但是viewgroup就必须实现。除此之外,在view中比较重要的两个绘制流程的方法onMeasure和onDraw在viewgroup中都没有被重写,相对于onMeasure方法,在viewgroup中增加了一些计算子view的方法,如measureChildren、measureChildrenWithMargins等,而对于onDraw方法,viewgroup则定义一个dispatchDraw方法来调用其每一个子view的onDraw方法,因此,我们自定义viewgroup的时候可以不需要实现onDraw方法。