组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。·
意思就是用树状结构来表示部分和整体,使他们具有一致性,一致性的意思就是都实现了相同的接口,举个例子,一个公司可能有研发部门和销售部门,然后这个公司又有子公司,子公司也有研发和销售部门,不论是总公司的部门还是子公司的部门,他们的职责其实是差不多的,当我们希望总公司的部门的职责复制到子公司时,就可以使用组合模式。我们看以下代码
//公司接口 public interface Company { void add(Company company); void remove(Company company); //展示树形结构 void display(int depth); //不同部门所具有的各自的职责 void duty(); }
// 具体公司类 树枝节点 public class ConcreteCompany implements Company { private List<Company> companyList = new ArrayList<>(); private String name; public ConcreteCompany(String name){ this.name = name; } @Override public void add(Company company) { companyList.add(company); } @Override public void remove(Company company) { companyList.remove(company); } @Override public void display(int depth) { StringBuffer stringBuffer = new StringBuffer("-"); for (int i = 0; i < depth ; i++) { stringBuffer.append("-"); } System.out.println(stringBuffer.append(name)); for (Company company: companyList) { company.display(depth+2); } } @Override public void duty() { for (Company company:companyList) { company.duty(); } } }
//部门类1 叶子节点 public class Department1 implements Company { private String name; public Department1(String name){ this.name = name; } @Override public void add(Company company) { } @Override public void remove(Company company) { } @Override public void display(int depth) { StringBuffer stringBuffer = new StringBuffer("-"); for (int i = 0; i < depth ; i++) { stringBuffer.append("-"); } System.out.println(stringBuffer.append(name)); } @Override public void duty() { System.out.println(name + "负责研发产品"); } }
//部门类2 叶子节点 public class Department2 implements Company { private String name; public Department2(String name){ this.name = name; } @Override public void add(Company company) { } @Override public void remove(Company company) { } @Override public void display(int depth) { StringBuffer stringBuffer = new StringBuffer("-"); for (int i = 0; i < depth ; i++) { stringBuffer.append("-"); } System.out.println(stringBuffer.append(name)); } @Override public void duty() { System.out.println(name + "负责销售"); } }
public class Test { public static void main(String[] args) { //根节点 ConcreteCompany root = new ConcreteCompany("总公司"); root.add(new Department1("总公司部门1")); root.add(new Department2("总公司部门2")); //子节点 ConcreteCompany comp = new ConcreteCompany("分公司"); comp.add(new Department1("分公司部门1")); comp.add(new Department2("分公司部门2")); root.add(comp); //叶子节点1 ConcreteCompany comp1 = new ConcreteCompany("办事处1"); comp1.add(new Department1("办事处1部门1")); comp1.add(new Department2("办事处1部门2")); comp.add(comp1); //叶子节点2 ConcreteCompany comp2 = new ConcreteCompany("办事处2"); comp2.add(new Department1("办事处2部门1")); comp2.add(new Department2("办事处2部门2")); comp.add(comp2); root.display(1); root.duty(); } }
测试结果:
–总公司
—-总公司部门1
—-总公司部门2
—-分公司
——分公司部门1
——分公司部门2
——办事处1
——–办事处1部门1
——–办事处1部门2
——办事处2
——–办事处2部门1
——–办事处2部门2
总公司部门1负责研发产品
总公司部门2负责销售
分公司部门1负责研发产品
分公司部门2负责销售
办事处1部门1负责研发产品
办事处1部门2负责销售
办事处2部门1负责研发产品
办事处2部门2负责销售
总结:从测试结果我们可以看到不同父节点的子节点相同的部门的职责是一样的,除此之外我们可以发现叶子节点实现了add()和remove()方法,因为这样叶子节点和其他节点对于外界没有区别,它们具有完全一致的行为接口,但是问题就是叶子节点是最底层的分支节点,实现添加和删除是没有意义的,给客户端带来了不安全性,这种方式就是透明方式。我们也可以在Company接口中不去声明这两个方法,这样安全性得到了提高,但是与此相对变得不再透明,树叶和树枝将不再具有相同的接口,客户端调用时就需要做相对应的判断。 当需求中体现整体与部分的层次结构,并且用户希望可以忽略组合对象与单个对象的不同,统一使用组合结构的所有对象时,我们就可以考虑使用组合模式。