组合模式
将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性
1. UML类图
2. 定义
- Component抽象构件角色:定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性
- Leaf叶子构件:叶子对象,其下再也没有其他的分支,也就是遍历的最小单位
- Composite树枝构件:树枝对象,它的作用是组合树枝节点和叶子节点形成一个树形结构
3. 通用代码
//抽象构件
public abstract class Component{
//个体和整体都具有的共享
public void doSomething(){
//编写业务逻辑
}
}
//树枝构件
public class Composite extends Component{
//构件容器
private ArrayList<Component> componentArrayList = new ArrayList<Component>();
//增加一个叶子构件或树枝构件
public void add(Component component){
this.componentArrayList.add(component);
}
//删除一个叶子构件或树枝构件
public void remove(Component component){
this.componentArrayList.remove(component);
}
//获得分支下的所有叶子构件和树枝构件
public ArrayList<Component> getChildren(){
return this.componentArrayList;
}
}
//树叶构件
public class Leaf extends Component{
//复写父类方法
public void doSomething(){
}
}
//场景类
public class client{
public static void main(String[] args){
//创建一个根节点
Composite root = new Composite();
root.doSomething();
//创建一个树枝构件
Composite branch = new Composite();
//创建一个叶子节点
Leaf leaf = new Leaf();
//建立整体
root.add(branch);
branch.add(leaf);
}
//通过递归遍历树
public static void display(Composite root){
for(Component c : root.getChildren){
if(c instanceof Leaf){
c.doSomething();
}else{
display((Composite)c);
}
}
}
}
4. 应用
4.1 优点
- 高层模块调用简单:一棵树形机构中的所有节点都是Component,局部和整体对调用者来说没有任何去呗,也就是说,高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码
- 节点自由增加:增加树枝节点,树叶节点都很容易,只要找到他的父节点就可以扩展,符合开闭原则
4.2 缺点
在场景类中直接使用了树叶和树枝的实现类,不符合面向接口编程的思想,与依赖倒置的原则冲突。
4.3 使用场景
- 维护和展示部分-整体关系的场景,如树形菜单、文件和文件夹管理
- 从一个整体中能够独立出部分模块或功能的场景
5. 透明的组合模式
组合模式有两种不同的实现:透明模式和安全模式,上述所讲的即是安全模式
5.1 UML类图
5.2 透明模式和安全模式
透明模式就是把用来组合使用的方法放到抽象类中,不管叶子对象还是树枝对象都有相同的结构,通过判断getChildren的返回值确认是叶子结点还是树枝节点,如果处理不当,这个会在运行期出现问题,不是很建议的方式;安全模式则将树枝节点和树叶节点彻底分开,树枝节点单独拥有用来组合的方法,这种方法比较安全
5.3 透明模式demo
//抽象构件
public abstract class Component{
//个体和整体都具有的共享
public void doSomething(){
//编写业务逻辑
}
//增加一个叶子构件或树枝构件
public void add(Component component);
//删除一个叶子构件或树枝构件
public void remove(Component component);
//获得分支下的所有叶子构件和树枝构件
public ArrayList<Component> getChildren();
}
//树枝构件
public class Composite extends Component{
//构件容器
private ArrayList<Component> componentArrayList = new ArrayList<Component>();
//增加一个叶子构件或树枝构件
public void add(Component component){
this.componentArrayList.add(component);
}
//删除一个叶子构件或树枝构件
public void remove(Component component){
this.componentArrayList.remove(component);
}
//获得分支下的所有叶子构件和树枝构件
public ArrayList<Component> getChildren(){
return this.componentArrayList;
}
}
//树叶构件
public class Leaf extends Component{
@Deprecated
public void add(Component component) throws UnsupportedOperationException{
throw new UnsupportedOperationException();
}
@Deprecated
public void remove(Component component) throws UnsupportedOperationException{
throw new UnsupportedOperationException();
}
@Deprecated
public ArrayList<Component> getChildren() throws UnsupportedOperationException{
throw new UnsupportedOperationException();
}
}
//通过递归遍历树
public static void display(Composite root){
for(Component c : root.getChildren){
if(c instanceof Leaf){
c.doSomething();
}else{
display(c);
}
}
}
5.4 优点
在遍历的时候不再进行强制类型转化,遵循了依赖倒置原则,方便系统扩展