设计模式源码git地址:design-pattern-src: 设计模式源码 (gitee.com)
定义
角色
类图
种类
场景举例
实际应用场景
总结
定义 组合模式定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理 。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合 ,形成一个树形结构。
角色 Component(抽象构件):声明公共行为
Leaf(叶子结点,树叶构件):没有子节点
Composite(树枝构件):存储或管理子部件,有独特的list
通用类图
以其他形式展现 在文件系统中可改写为如图,文件为抽象类定义了对象的一些属性及方法,具体的由文件夹和文件去实现,而文件只实现操作方法(getName)
而在别的场景中,如组织结构,这个文件夹就相当于一个统称了,比如一级部门下有二级,二级下有三级,等等,那么最后一级部门作为叶子节点,其余部门就全部充当树枝节点了
种类 组合模式有透明方式 与安全方式
透明方式表示用户使用的时候不管是叶子还是树枝方法都是一样的,用户全能看到方法,但如果叶子结点调用add方法,就会出现异常
安全方式则针对于透明方式,透明方式出现异常的地方弄安全就叫安全模式,使叶子节点不实现add方法就好了
所以决定透明还是安全的就在于抽象构件这个怎么去定义
场景举例 现需要展示公司的部门层级,如何实现?
先构建类图,捋清楚之前的关系(找到了一个画图软件,比mspaint好用多了)
再看client如何调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 //创建公司 Component company = new CompanyComposite("北京公司"); //创建部门 Component dept1 = new DeptComposite("财务部"); Component dept2 = new DeptComposite("市场部"); //创建叶子节点 Component leaf = new Leaf("最小部门"); //将部门加到公司中 company.add(dept1); company.add(dept2); //将最小部门加到部门中 dept1.add(leaf); dept2.add(leaf); //输出组织架构 company.getChild(); System.out.println("-------"); dept1.getChild();
输出截图
抽象接口定义(这里使用了接口,并使用了Java8的默认接口特性,子类可以选择不实现)
1 2 3 4 5 6 7 public interface Component { String getName () ; default void add (Component o) { }; default Component getChild () { return null ; }; }
公司实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class CompanyComposite implements Component { private String name; private List<Component> organizationComponents = new ArrayList<>(); public CompanyComposite (String name) { this .name = name; } @Override public String getName () { return name; } @Override public void add (Component o) { organizationComponents.add(o); } @Override public Component getChild () { for (Component temp : organizationComponents) { if (temp != null ) { System.out.println(name+"下有" +temp.getName()); temp.getChild(); } } return null ; } }
部门实现类(与公司大体一致,实际情况考虑到业务不同,树枝类不写到一坨)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class DeptComposite implements Component { private String name; private List<Component> organizationComponents = new ArrayList<>(); public DeptComposite (String name) { this .name = name; } @Override public String getName () { return name; } @Override public void add (Component o) { organizationComponents.add(o); } @Override public Component getChild () { for (Component temp : organizationComponents) { if (temp != null ) { System.out.println(name+"下有" +temp.getName()); temp.getChild(); } } return null ; } }
叶子部门实现类
1 2 3 4 5 6 7 8 9 10 11 12 public class Leaf implements Component { private String name; public Leaf (String name) { this .name = name; } @Override public String getName () { return name; } }
实际应用场景 ①在List中定义addAll()的方法为
1 boolean addAll (Collection<? extends E> c) ;
这里的collection可以看作上面的Component
②JDK中AWT包和Swing包的设计是基于组合模式 ,在这些界面包中为用户提供了大量的容器构件,继承、关联于组件类Component
举个例子,比如Container类,其中的add方法
1 2 3 4 public Component add (Component comp) { addImpl(comp, null , -1 ); return comp; }
remove方法
1 2 3 4 5 6 7 8 9 10 public void remove (Component comp) { synchronized (getTreeLock()) { if (comp.parent == this ) { int index = component.indexOf(comp); if (index >= 0 ) { remove(index); } } } }
总结 1、可以递归组合成任意复杂的对象
2、可随意增加新类型的Composite与Leaf的类
3、采用同一套接口操作
4、由于返回的使同一个接口类型,必要的时候需要做类型判断