组合模式(Composite)将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得客户对单个对象和复合对象的使用具有一致性。
需求:公司管理系统的设计,公司有多个部门,总公司又含有子公司。
示例
定义公司对象的抽象父类,定义具体的职责:
public abstract class Company {
protected String name;
public Company(String name) {
this.name = name;
}
//增加公司
public abstract void add(Company company);
//移除公司
public abstract void remove(Company company);
//显示
public abstract void display(int depth);
//部门履行的职责
public abstract void lineOfDuty();
}
公司的实现类:
public class ConcreteCompany extends Company {
public List<Company> chldren = new ArrayList<>();
public ConcreteCompany(String name) {
super(name);
}
@Override
public void add(Company company) {
chldren.add(company);
}
@Override
public void remove(Company company) {
chldren.remove(company);
}
@Override
public void display(int depth) {
StringBuilder sb =new StringBuilder(depth);
for (int i = 0; i < depth; i++) {
sb.append("-");
}
System.out.println(sb+ name);
for (Company c : chldren
) {
c.display(depth + 2);
}
}
@Override
public void lineOfDuty() {
for (Company c : chldren
) {
c.lineOfDuty();
}
}
}
定义公司的部门–人事部
public class HRDepartment extends Company {
public HRDepartment(String name) {
super(name);
}
@Override
public void add(Company company) {
}
@Override
public void remove(Company company) {
}
@Override
public void display(int depth) {
StringBuilder sb = new StringBuilder(depth);
for (int i = 0; i < depth; i++) {
sb.append("-");
}
System.out.println(sb + name);
}
@Override
public void lineOfDuty() {
System.out.println(name + "人事管理");
}
}
再来一个财务部
public class FinanceDepartment extends Company {
public FinanceDepartment(String name) {
super(name);
}
@Override
public void add(Company company) {
}
@Override
public void remove(Company company) {
}
@Override
public void display(int depth) {
StringBuilder sb = new StringBuilder(depth);
for (int i = 0; i < depth; i++) {
sb.append("-");
}
System.out.println(sb + name);
}
@Override
public void lineOfDuty() {
System.out.println(name + "财务管理");
}
}
到此,我们就可以创建一个公司,而且公司里可以有财务部和人事部了;运行测试:
public void compositeTest() {
ConcreteCompany root = new ConcreteCompany("北京总公司");
root.add(new HRDepartment("总公司人事部"));
root.add(new FinanceDepartment("总公司财务部"));
ConcreteCompany sh = new ConcreteCompany("上海分公司");
sh.add(new HRDepartment("上海分公司人事部"));
sh.add(new FinanceDepartment("上海分公司财务部"));
root.add(sh);
ConcreteCompany nj = new ConcreteCompany("南京分公司");
nj.add(new HRDepartment("南京分公司人事部"));
nj.add(new FinanceDepartment("南京分公司财务部"));
root.add(nj);
ConcreteCompany hk = new ConcreteCompany("香港分公司");
hk.add(new HRDepartment("香港分公司人事部"));
hk.add(new FinanceDepartment("香港分公司财务部"));
root.add(hk);
root.display(1);
root.lineOfDuty();
}
运行结果: -北京总公司 ---总公司人事部 ---总公司财务部 ---上海分公司 -----上海分公司人事部 -----上海分公司财务部 ---南京分公司 -----南京分公司人事部 -----南京分公司财务部 ---香港分公司 -----香港分公司人事部 -----香港分公司财务部 总公司人事部人事管理 总公司财务部财务管理 上海分公司人事部人事管理 上海分公司财务部财务管理 南京分公司人事部人事管理 南京分公司财务部财务管理 香港分公司人事部人事管理 香港分公司财务部财务管理
如果我们需要新增一个子公司或者是部门,只需要声明相关的对象即可。
透明方式与安全方式
上面的实现方式为透明方式:
也就是说在Component(Company)中声明所有来管理子对象的方法,其中包括add,remove等。这样实现的Component接口的所有子类都具备了add和remove。这样做的好处就是叶节点和枝节点对于外界没有区别,他们具备完全一致的行为接口。但问题也很明显,因为叶节点本身不具备ADD(),REMOVE()方法的功能,所以实现它是没有意义的。
安全方式:在Component中不去声明add和remove方法,那么子类的叶节点就不需要去实现它,而在Composite声明所有来管理子类对象的方法。不过由于不够透明,所有树叶和树枝类将不具备相同的接口,客户端的调用需要做相应的判断,带来了不便。
何时使用组合模式:当发现需求中是体现部分与整体层次的结构是,以及你希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,就应该考虑组合模式了。
例子来源及参考资料:《大话设计模式》
本文地址:http://blog.csdn.net/ProdigalWang/article/details/78212030