写点什么

CompositePattern- 组合模式

作者:梁歪歪 ♚
  • 2022 年 5 月 31 日
  • 本文字数:4226 字

    阅读完需:约 14 分钟

CompositePattern-组合模式

在编码原则中,有一条是:多用组合,少用继承。这里面的组合与我们今天要学的组合模式是不等价的,这里的组合其实是一种聚合,而聚合和组合有着本质的区别。

组合模式

1、组合和聚合

聚合各个对象聚合在一起工作,但是”我“没有你也行,”我“照样可以正常运行工作。聚合对象不具备相同生命周期。

组合各个对象之间组成了一个整体,缺一不可,”我“没有了你,可能我就不能正常运行工作,可能功能上就会造成很大的缺陷。组合对象具有相同的生命周期。


示例

  • 组合关系:一个公司由多个部门组成,部门撤销了,员工不会消失。

  • 聚合关系:一个部门由多个员工组成,公司不存在了,那么部门也随之不存在了。


上述例子可能有些许不妥当,但也能较为直观的说清楚二者的区别。

2、什么是组合模式

组合模式(Composite Pattern):也称之为整体-部分(Part-Whole)模式,是用于把一组相似的对象当作一个单一的对象。组合模式的核心是通过将单个对象(叶子节点)和组合对象(树枝节点)用相同的接口进行表示,使得单个对象和组合对象的使用具有一致性,组合模式属于结构型模式。



组合模式又分为:透明模式和安全模式

3、透明模式

示例:我们通过高考科目来举例说明组合模式中的透明模式


  • 高考科目的抽象类GkAbstractCourse.java


package cn.liangyy.composite.transparency;
/** * 高考科目的抽象类 */public abstract class GkAbstractCourse { /** * 添加子节点 * @param course */ public void addChild(GkAbstractCourse course){ System.out.println("不支持添加操作!"); }
/** * 获取当前节点名称 * @return * @throws Exception */ public String getName() throws Exception { throw new Exception("不支持获取名称!"); }
/** * 获取高考科目信息 * @throws Exception */ public void info() throws Exception { throw new Exception("不支持查询信息操作!"); }}
复制代码


想必这里大家有疑问,为什么不将这些方法定义为抽象方法,而是默认都抛出异常?假如定义为抽象方法,那么所有的子类都必须重写父类方法。这种抛异常的方式,完全根据子类需要用到的功能去重写覆盖父类方法即可。


  • 普通高考科目类LeafCource.java


package cn.liangyy.composite.transparency;
/** * 普通高考科目类(叶子节点) * 无法包含其他科目 */public class LeafCource extends GkAbstractCourse { //课程名称 private String name; //课程分数 private String score;
public LeafCource(String name, String score) { this.name = name; this.score = score; }
/** * 获取当前节点名称 * @return * @throws Exception */ @Override public String getName() { return this.name; }
/** * 获取高考科目信息 * @throws Exception */ @Override public void info() { System.out.println("课程:"+ this.name + ",分数:"+ score); }}
复制代码


  • 树枝类BranchCource.java


package cn.liangyy.composite.transparency;
import java.util.ArrayList;import java.util.List;
/** * 树枝类 * 可以包含其他科目的类 */public class BranchCource extends GkAbstractCourse { private List<GkAbstractCourse> courseList = new ArrayList<>(); //科目名称 private String name; //层级 private int level;
public BranchCource(String name, int level) { this.name = name; this.level = level; }
/** * 添加子节点(子课程) * @param course */ @Override public void addChild(GkAbstractCourse course) { courseList.add(course); }
/** * 获取当前节点名称(课程名称) * @return * @throws Exception */ @Override public String getName() throws Exception { return this.name; }
/** * 获取高考科目信息 * @throws Exception */ @Override public void info() throws Exception { //打印课程信息 System.out.println("课程:"+this.name); for (GkAbstractCourse course : courseList) { //根据层级关系打印空格,这样打印结果可以明显看出层级关系 for (int i = 0; i < level; i++) { System.out.print(" "); } System.out.print(">"); course.info(); } }}
复制代码


  • 测试TestTransparency.java


package cn.liangyy.composite.transparency;
/** * 透明模式-测试 */public class TestTransparency { public static void main(String[] args) throws Exception { GkAbstractCourse ywCourse = new LeafCource("语文","150"); GkAbstractCourse sxCourse = new LeafCource("数学","150"); GkAbstractCourse yyCourse = new LeafCource("英语","150");
GkAbstractCourse wlCourse = new LeafCource("物理","110"); GkAbstractCourse hxCourse = new LeafCource("化学","100"); GkAbstractCourse swCourse = new LeafCource("生物","90");
GkAbstractCourse lzCourse = new BranchCource("理综",2); lzCourse.addChild(wlCourse); lzCourse.addChild(hxCourse); lzCourse.addChild(swCourse);
GkAbstractCourse lkgkCourse = new BranchCource("理科高考",1); lkgkCourse.addChild(ywCourse); lkgkCourse.addChild(sxCourse); lkgkCourse.addChild(yyCourse);
lkgkCourse.addChild(lzCourse); lkgkCourse.info();
//这里会输出"不支持添加操作!",叶子节点无法再添加 ywCourse.addChild(sxCourse); }}
复制代码


上面就是一个透明模式的写法,它的父类将所有的方法都定义好了,对各个子类完全透明,所有才将它称为透明模式。优点:客户端无需分辨当前对象时属于树枝节点还是叶子节点,因为它们具备了完全一致的接口。缺点:就是叶子节点能得到不属于它的方法,比如上述例子中的==ywCourse.addChild(sxCourse);==,这个很明显违背了接口隔离性原则。

4、安全模式

我们通过高考科目来举例说明组合模式中的安全模式


  • 顶层的抽象课程类GkAbstractCourse.java


package cn.liangyy.composite.safe;
/** * 抽象课程类(顶层) */public abstract class GkAbstractCourse { //课程名称 protected String name; //课程分数 protected String score;
public GkAbstractCourse(String name, String score) { this.name = name; this.score = score; }
/** * 获取课程信息 */ public abstract void info();}
复制代码


  • 普通高考科目类LeafCource.java


package cn.liangyy.composite.safe;
/** * 普通高考科目类(叶子节点) */public class LeafCource extends GkAbstractCourse { public LeafCource(String name,String score){ super(name,score); } /** * 获取课程信息 */ @Override public void info() { System.out.println("课程:"+ this.name +",分数:"+ this.score); }}
复制代码


  • 树枝类BranchCource.java


package cn.liangyy.composite.safe;
import java.util.ArrayList;import java.util.List;
/** * 树枝类 */public class BranchCource extends GkAbstractCourse { //子课程 private List<GkAbstractCourse> courseList = new ArrayList<>(); //层级 private int level;
public BranchCource(String name, String score, int level) { super(name, score); this.level = level; }
//添加子课程 public void addChild(GkAbstractCourse course){ courseList.add(course); }
/** * 获取课程信息 */ @Override public void info() { //打印课程信息 System.out.println("课程:"+ this.name +",分数:"+ this.score); for (GkAbstractCourse course : courseList) { for (int i = 0; i < level; i++) { //根据层级关系打印空格 System.out.print(" "); } System.out.print(">"); course.info(); } }}
复制代码


  • 测试TestSafe.java


package cn.liangyy.composite.safe;
/** * 安全模式-测试 */public class TestSafe { public static void main(String[] args) { GkAbstractCourse ywCourse = new LeafCource("语文","150"); GkAbstractCourse sxCourse = new LeafCource("数学","150"); GkAbstractCourse yyCourse = new LeafCource("英语","150");
GkAbstractCourse wlCourse = new LeafCource("物理","110"); GkAbstractCourse hxCourse = new LeafCource("化学","100"); GkAbstractCourse swCourse = new LeafCource("生物","90");
BranchCource lzCourse = new BranchCource("理综","300",2); lzCourse.addChild(wlCourse); lzCourse.addChild(hxCourse); lzCourse.addChild(swCourse);
BranchCource lkgkCourse = new BranchCource("理科高考","750",1); lkgkCourse.addChild(ywCourse); lkgkCourse.addChild(sxCourse); lkgkCourse.addChild(yyCourse);
lkgkCourse.addChild(lzCourse); lkgkCourse.info(); }}
复制代码


组合模式适用场景组合模式一般应用在有层级关系的场景,最经典的就是树形菜单、文件和文件夹的管理等。


组合模式优点组合模式清楚的定义了分层次的复杂对象,让客户端可以忽略层次的差异,方便对整个层次进行动态控制。


组合模式缺点组合模式的叶子和树枝的声明是实现类而不是接口,违反了依赖倒置原则,而且组合模式会使设计更加抽象不好理解。

发布于: 刚刚阅读数: 3
用户头像

梁歪歪 ♚

关注

还未添加个人签名 2021.07.22 加入

还未添加个人简介

评论

发布
暂无评论
CompositePattern-组合模式_设计模式_梁歪歪 ♚_InfoQ写作社区