组合设计模式
将对象组合成树形结构,以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
1. 使用场景
当用户需要忽略组合对象和单个对象的不同,统一使用组合结构中的所有对象时,可使用该模式。
当用户调用根节点的方法时,会调用树中所有节点的方法。
2. 角色
首先树状结构肯定含有根节点、分枝节点、叶子节点。
- Component 抽象根节点,规定了节点拥有的方法。
- Composite 定义枝干节点的行为,存储子节点。
- Leaf 定义叶子节点,定义节点行为。
3. 实践
安全的组合模式:是指分枝和叶子节点使用不同的类型,客户端调用时,需要直接使用Component的实现类。缺点在于违背了依赖倒置原则,用户依赖节点具体实现。不是面向接口编程。
// 1.定义抽象根节点
public abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
// 具体的逻辑方法由子类实现
public abstract void doSomething();
}
// 2.定义枝干节点,实现对子节点的操作,实现分枝节点规定的行为
public class Composite extends Component {
// 存储节点的容器
private List<Component> mComponents = new ArrayList<>();
public Composite(String name) {
super(name);
}
@Override
public void doSomething() {
System.out.println(name);
// 叶子节点么有list,肯定为空
if (null != mComponents) {
for (Component c : mComponents) {
c.doSomething();
}
}
}
public void addChild(Component child) {
mComponents.add(child);
}
public void removeChild(Component child) {
mComponents.remove(child);
}
public Component getChild(int index) {
return mComponents.get(index);
}
}
// 3.定义叶子节点,规定叶子节点的行为
public class Leaf extends Component {
public Leaf(String name) {
super(name);
}
@Override
public void doSomething() {
System.out.println(name);
}
}
/**
* 组合对象,调用方法,安全的组合模式,
*/
Composite root = new Composite("Root");
Composite branch1 = new Composite("Branch1");
Composite branch2 = new Composite("Branch2");
Leaf leaf1 = new Leaf("Leaf1");
Leaf leaf2 = new Leaf("Leaf2");
Leaf leaf3 = new Leaf("Leaf3");
Leaf leaf4 = new Leaf("Leaf4");
root.addChild(branch1);
root.addChild(branch2);
branch1.addChild(leaf1);
branch1.addChild(leaf3);
branch2.addChild(leaf2);
branch2.addChild(leaf4);
root.doSomething();
透明的组合模式 指组合结构中所有节点都有着相同的结构,在方法内部区分不同节点。符合依赖倒置原则。
// 1. 定义抽象根节点,包含了分枝节点和叶子节点的所有方法。
public abstract class Dir {
protected List<Dir> mDirs=new ArrayList<>();
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;
}
}
// 2. 分枝节点的具体实现。
public class Folder extends Dir {
public Folder(String name) {
super(name);
}
@Override
public void addDir(Dir dir) {
mDirs.add(dir);
}
@Override
public void rmDir(Dir dir) {
mDirs.remove(dir);
}
@Override
public void clear() {
mDirs.clear();
}
@Override
public void print() {
System.out.print(getName() + "(");
Iterator<Dir> iter = mDirs.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 null;
}
}
// 3. 叶子节点具体实现,屏蔽叶子节点不支持的方法。
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("文件对象不支持该操作!");
}
}
/**
* 以下是透明的组合模式,叶子节点屏蔽了部分方法。
*/
Dir diskC=new Folder("C");
diskC.addDir(new File("imdb.txt"));
Dir dirWin=new Folder("Windows");
dirWin.addDir(new File("explorer.exe"));
diskC.addDir(dirWin);
Dir dirPer=new Folder("PerfLogs");
dirPer.addDir(new File("null.txt"));
diskC.addDir(dirPer);
Dir dirPro=new Folder("ProgramFile");
dirPro.addDir(new File("ftp.txt"));
diskC.addDir(dirPro);
diskC.print();
4. 总结
View 和 ViewGroup 就是使用的组合模式