目录
组合(Composite)模式
本质:统一叶子对象和组合对象
组合模式也叫部分-整体模式。组合模式将对象组织到树结构中,可以用来描述整体与部分的关系,可以使客户端将单纯元素与复合元素同等看待。
适用场景
- 树形结构。
- 需求中是体现部分与整体的结构。
让客户端统一操作组合对象和叶子对象,不再区分二者。如树形菜单、文件和文件夹管理,读XML文件等。
UML图(透明方式)
抽象构件(Component)角色:
给参与组合的对象规定共有方法和属性
树叶构件(Leaf)角色:
树叶对象,没有下级子对象。
树枝构件(Composite)角色:
树枝对象,有下级子对象,并实现Component类中规定的方法。
public abstract class Component {
protected String name;
public Component(String name) {
super();
this.name = name;
}
public abstract void add(Component c);
public abstract void remove(Component c);
public abstract void display(int depth);
}
import java.util.ArrayList;
public class Composite extends Component{
private ArrayList<Component> children=new ArrayList<Component>();
public Composite(String name) {
super(name);
}
@Override
public void add(Component c) {
children.add(c);
}
@Override
public void remove(Component c) {
children.remove(c);
}
@Override
public void display(int depth) {
System.out.println(depth+name);
for(Component component :children){
component.display(depth+1);
}
}
}
public class Leaf extends Component{
public Leaf(String name) {
super(name);
}
@Override
public void add(Component c) {
//空实现,抛出一个"不支持请求"异常
throw new UnsupportedOperationException();
}
@Override
public void remove(Component c) {
throw new UnsupportedOperationException();
}
@Override
public void display(int depth) {
System.out.println(depth+name);
}
}
public class Main {
public static void main(String[] args) {
//根节点
Composite root=new Composite("root");
//树枝
Composite b1=new Composite("branch1");
Leaf y1=new Leaf("leaf1");
Leaf y2=new Leaf("leaf2");
root.add(b1);
b1.add(y1);
b1.add(y2);
root.display(0);
}
}
安全模式和透明模式
组合模式的实现根据所实现接口的区别分为两种形式:安全模式和透明模式。
组合模式必须在合适的地方提供子对象的管理方法,如:add、remove、display等。
透明方式
在抽象类Component声明所有用来管理子类对象的方法,包括add,emove,display等,通过getChildren的返回值确认是叶子节点还是树枝节点
优点:树叶和树枝类有相同的接口。
树叶对象与树枝对象的区别起码在接口层次上消失了,客户端可以同等的对待所有的对象。
缺点:不够安全。
但树枝对象和叶子对象本质上是有区别的,叶子没有子对象,因此add,remove,display等方法没有意义,如果叶子生成子对象,在编译时期不会出错,而会在运行时出错。
安全方式
在Composite类里面声明所有的用来管理子类对象的方法
优点:安全。把树枝节点和树叶节点彻底分开,叶子没有管理子类对象的方法。
缺点:不够透明,树叶类和树枝类将具有不同的接口。
真实的组合模式
这张表定义了一个树形结构,我们要做的就是从数据库中把它读取出来,然后展现到前台上,用for循环加上递归就可以完成这个读取。用了数据库后,数据和逻辑已经在表中定义好了,我们直接读取放到树上就可以了。
优缺点
优点:
- 简化了客户端调用。一棵树形机构中的所有节点都是Component,统一了组合对象和叶子对象。
- 容易扩展。如果想增加一个树枝节点、树叶节点,只要找到它的父节点就成。
缺点:
- 需要检测组件类型的时候,不能依靠编译期完成,必须在运行期间检测
-
直接使用了实现类,与依赖倒置原则冲突
实例——公司人员
public abstract class Company {
protected String name;
protected String pos;
public Company(String name, String pos) {
super();
this.name = name;
this.pos = pos;
}
public abstract void add(Company c);
public abstract void remove(Company c);
public abstract void display(int depth);
}
package com.oa;
import java.util.ArrayList;
import java.util.List;
import com.test.Component;
public class ConcreteCompany extends Company{
public ConcreteCompany(String name, String pos) {
super(name, pos);
}
private List<Company> children=new ArrayList<Company>();
@Override
public void add(Company c) {
children.add(c);
}
@Override
public void remove(Company c) {
children.remove(c);
}
@Override
public void display(int depth) {
System.out.println(depth+":"+name+","+pos);
for(Company company :children) {
company.display(depth+1);
}
}
}
package com.oa;
public class Leaf extends Company{
public Leaf(String name, String pos) {
super(name, pos);
}
@Override
public void add(Company c) {
throw new UnsupportedOperationException();
}
@Override
public void remove(Company c) {
throw new UnsupportedOperationException();
}
@Override
public void display(int depth) {
System.out.println(depth+":"+name+","+pos);
}
}
package com.oa;
public class Main {
public static void main(String[] args) {
ConcreteCompany root=new ConcreteCompany("李华","CEO");
ConcreteCompany b1=new ConcreteCompany("张三","经理");
ConcreteCompany b2=new ConcreteCompany("小红","经理");
Leaf y1=new Leaf("李四","员工");
Leaf y2=new Leaf("王五","员工");
Leaf y3=new Leaf("王明","员工");
root.add(b1);
b1.add(y1);
b1.add(y2);
root.add(b2);
b2.add(y3);
root.display(0);
}
}