将对象组合成树形结构以表示“部分-总体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具备一致性。安全
/** * 组合对象 * Created by callmeDevil on 2019/8/11. */ public abstract class Component { protected String name; public Component(String name){ this.name = name; } // 一般都用add 和remove 方法来提供增长或移除树叶或树枝的功能 public abstract void add(Component c); public abstract void remove(Component c); public abstract void dispaly(int depth); }
/** * 枝节点行为,用来存储子部件 * Created by callmeDevil on 2019/8/11. */ public class Composite extends Component{ // 一个子对象集合用来存储其下属枝节点和叶节点 private List<Component> children = new ArrayList<>(); 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 dispaly(int depth) { StringBuilder sb = new StringBuilder(depth); for (int i = 0; i < depth; i++) { sb.append("-"); } // 显示枝节点名称,并对其下级进行遍历 System.out.println(String.format("%s %s", sb.toString(), name)); for (Component child : children) { child.dispaly(depth + 3); } } }
/** * 叶节点对象 * Created by callmeDevil on 2019/8/11. */ public class Leaf extends Component { public Leaf(String name) { super(name); } @Override public void add(Component c) { System.out.println("cannot add to a leaf"); } @Override public void remove(Component c) { System.out.println("cannot remove from a leaf"); } @Override public void dispaly(int depth) { StringBuilder sb = new StringBuilder(depth); for (int i = 0; i < depth; i++) { sb.append("-"); } // 显示名称和级别 System.out.println(String.format("%s %s", sb.toString(), name)); } }
public class Test { public static void main(String[] args) { // 生成树根root,根上长出两叶LeafA 和LeafB Composite root = new Composite("root"); root.add(new Leaf("Leaf A")); root.add(new Leaf("Leaf B")); // 根上长出分枝 Composite X ,分枝上也有两叶LeafXA 和LeafXB Composite comp = new Composite("Composite X"); comp.add(new Leaf("Leaf XA")); comp.add(new Leaf("Leaf XB")); root.add(comp); // 分枝 Composite X上再长出分枝 Composite XY ,分枝上也有两叶Leaf XYA 和Leaf XYB Composite comp2 = new Composite("Composite XY"); comp2.add(new Leaf("Leaf XYA")); comp2.add(new Leaf("Leaf XYB")); comp.add(comp2); // 根部又长出两叶LeafC 和LeafD,惋惜LeafD没长牢,被风吹走了 root.add(new Leaf("Leaf C")); Leaf leafD = new Leaf("Leaf D"); root.add(leafD); root.remove(leafD); // 显示大树 root.dispaly(1); } }
- root ---- Leaf A ---- Leaf B ---- Composite X ------- Leaf XA ------- Leaf XB ------- Composite XY ---------- Leaf XYA ---------- Leaf XYB ---- Leaf C
树可能有无数的分枝,反复使用 Composite 就能够实现树状结构,但树叶不能够再长分枝,为何此处 Leaf 当中也有实现 add 和 remove?app
这种叫作透明方式,也就是说在 Component 中声明全部用来管理子对象的方法,其中包括 add, remove 等。这样实现 Component 接口的全部子类都具有了 add 和 remove。这样作的好处是叶节点和枝节点对于外界没有区别,它们具有彻底一致的行为接口,但问题也明显,由于自己不具体 add 和 remove 功能,因此实现是没有意义的。ide
固然也能够不去实现,这种叫作安全方式,也就是在 Component 接口中不去声明 add 和 remove 方法,那么子类的 Leaf 也就不须要去实现,而是在 Composite 声明全部用来管理子类对象的方法,不过因为不够透明,因此树叶和树枝将不具备相同的接口,客户端的调用须要作相应的判断,带来了不便。测试
当需求中是体现部分与总体层次的结构时,以及但愿用户能够忽略组合对象与单个对象的不一样,统一的使用组合结构中的全部对象时,就应该考虑用组合模式了。ui
总公司与分公司关系,总公司的全部管理功能一样能使用在分公司。this
/** * 公司抽象类 * Created by callmeDevil on 2019/8/11. */ public abstract class Company { protected String name; public Company(String name){ this.name = name; } public abstract void add(Company c); public abstract void remove(Company c); public abstract void dispaly(int depth); public abstract void lineOfDuty(); // 履行职责,不一样部门须要履行不一样的职责 // 用于输出层次结构,非必须,与模式无关 public String getDepth(int depth){ StringBuilder sb = new StringBuilder(depth); for (int i = 0; i < depth; i++) { sb.append("-"); } return sb.toString(); } }
/** * 具体公司(树枝节点) * Created by callmeDevil on 2019/8/11. */ public class ConcreteCompany extends Company { private List<Company> children = new ArrayList<>(); public ConcreteCompany(String name) { super(name); } @Override public void add(Company c) { children.add(c); } @Override public void remove(Company c) { children.remove(c); } @Override public void dispaly(int depth) { System.out.println(String.format("%s %s", getDepth(depth), name)); for (Company child : children) { child.dispaly(depth + 3); } } @Override public void lineOfDuty() { for (Company child : children) { child.lineOfDuty(); } } }
/** * 人力资源部(树叶节点) * Created by callmeDevil on 2019/8/11. */ public class HRDepartment extends Company{ public HRDepartment(String name){ super(name); } @Override public void add(Company c) {} @Override public void remove(Company c) {} @Override public void dispaly(int depth) { System.out.println(String.format("%s %s", getDepth(depth), name)); } @Override public void lineOfDuty() { System.out.println(String.format("%s 员工招聘培训管理", name)); } }
/** * 财务部(树叶节点) * Created by callmeDevil on 2019/8/11. */ public class FinanceDepartment extends Company{ public FinanceDepartment(String name){ super(name); } @Override public void add(Company c) {} @Override public void remove(Company c) {} @Override public void dispaly(int depth) { System.out.println(String.format("%s %s", getDepth(depth), name)); } @Override public void lineOfDuty() { System.out.println(String.format("%s 公司财务收支管理", name)); } }
public class Test { public static void main(String[] args) { ConcreteCompany root = new ConcreteCompany("北京总公司"); root.add(new HRDepartment("总公司人力资源部")); root.add(new FinanceDepartment("总公司财务部")); ConcreteCompany comp = new ConcreteCompany("上海分公司"); comp.add(new HRDepartment("上海分公司人力资源部")); comp.add(new FinanceDepartment("上海分公司财务部")); root.add(comp); ConcreteCompany comp1 = new ConcreteCompany("南京办事处"); comp1.add(new HRDepartment("南京办事处人力资源部")); comp1.add(new FinanceDepartment("南京办事处财务部")); comp.add(comp1); ConcreteCompany comp2 = new ConcreteCompany("杭州办事处"); comp2.add(new HRDepartment("杭州办事处人力资源部")); comp2.add(new FinanceDepartment("杭州办事处财务部")); comp.add(comp2); System.out.println("\n 结构图:"); root.dispaly(1); System.out.println("\n 职责:"); root.lineOfDuty(); } }
结构图: - 北京总公司 ---- 总公司人力资源部 ---- 总公司财务部 ---- 上海分公司 ------- 上海分公司人力资源部 ------- 上海分公司财务部 ------- 南京办事处 ---------- 南京办事处人力资源部 ---------- 南京办事处财务部 ------- 杭州办事处 ---------- 杭州办事处人力资源部 ---------- 杭州办事处财务部 职责: 总公司人力资源部 员工招聘培训管理 总公司财务部 公司财务收支管理 上海分公司人力资源部 员工招聘培训管理 上海分公司财务部 公司财务收支管理 南京办事处人力资源部 员工招聘培训管理 南京办事处财务部 公司财务收支管理 杭州办事处人力资源部 员工招聘培训管理 杭州办事处财务部 公司财务收支管理