定义:
组合模式(Composite Pattern)又称为合成模式、部分-整体模式(Part-Whole),主要用来描述部分与整体的关系。 定义:将对象组合成树形结构以表示“部分-整体”的层次结构,使用户对单个对象和组合对象的使用具有一致性
本章代码:小麻雀icknn/设计模式练习 - Gitee.com
结构:
- 组件(Component):是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
- 叶子节点(Leaf):在组合中表示叶子结点对象,叶子结点没有子结点。
- 复合节点(Composite):定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。
UML类图:
组合模式的分类
组合模式分为透明式的组合模式和安全式的组合模式。
透明方式
- 透明模式的特点就是将组合对象所有的公共方法都定义在了抽象组件内,这样做的好处是客户端无需分辨当前对象是属于树枝节点还是叶子节点,因为它们具备了完全一致的接口,不过缺点就是叶子节点得到到了一些不属于它的方法,比如上面的addchild方法,这违背了接口隔离性原则。
安全方式
- 在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题。
- 但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。
实例:
透明模式:
组件(Component)根节点
package com.study.composite.transprant;
public abstract class GKAbstractCourse {
public void addChild(GKAbstractCourse gkAbstractCourse){
System.out.println("不支持添加操作");
}
public String getName() throws Exception{
throw new Exception("不支持获取名称");
}
public void info() throws Exception{
throw new Exception("不支持查询");
}
}
叶子节点(Leaf)
package com.study.composite.transprant;
import java.util.ArrayList;
import java.util.List;
public class LevelCourse extends GKAbstractCourse {
private List<GKAbstractCourse> levelCourseList =new ArrayList<>();
private String name;
public LevelCourse(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public void addChild(GKAbstractCourse gkAbstractCourse) {
levelCourseList.add(gkAbstractCourse);
}
@Override
public void info() throws Exception {
for (GKAbstractCourse gkAbstractCourse : levelCourseList) {
gkAbstractCourse.info();
}
}
}
复合节点(Composite)
package com.study.composite.transprant;
public class CommonCourse extends GKAbstractCourse {
private String name;
private String score;
public CommonCourse(String name,String score){
this.name = name;
this.score = score;
}
@Override
public String getName() {
return name;
}
public String getScore() {
return score;
}
@Override
public void info() throws Exception {
System.out.println("科目:" + this.getName());
System.out.println("分数:" + this.getScore());
}
}
安全模式:
组件(Component)根节点
package com.study.composite.safe;
public abstract class GKAbstractSafeCourse {
String name;
String score;
public GKAbstractSafeCourse(String name, String score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public String getScore() {
return score;
}
public abstract void info();
}
叶子节点(Leaf)
package com.study.composite.safe;
import java.util.ArrayList;
import java.util.List;
public class LevelSafeCourse extends GKAbstractSafeCourse {
private List<GKAbstractSafeCourse> levelCourseList =new ArrayList<>();
public LevelSafeCourse(String name, String score) {
super(name, score);
}
public void addChild(GKAbstractSafeCourse gkAbstractSafeCourse){
this.levelCourseList.add(gkAbstractSafeCourse);
}
@Override
public void info() {
System.out.println("科目:"+ this.getName() + "总分:" + this.getScore() );
for (GKAbstractSafeCourse item : this.levelCourseList) {
item.info();
}
}
}
复合节点(Composite)
package com.study.composite.safe;
public class CommonSafeCourse extends GKAbstractSafeCourse {
public CommonSafeCourse(String name, String score){
super(name,score);
}
@Override
public void info() {
System.out.println("科目:" + this.getName());
System.out.println("分数:" + this.getScore());
}
}
结果&&运行
import com.study.composite.safe.CommonSafeCourse;
import com.study.composite.safe.LevelSafeCourse;
import com.study.composite.transprant.CommonCourse;
import com.study.composite.transprant.LevelCourse;
public class Main {
public static void main(String[] args) throws Exception {
System.out.println("Hello world!");
CommonCourse chinese = new CommonCourse("语文", "120");
CommonCourse English = new CommonCourse("英语", "100");
CommonCourse Math = new CommonCourse("数学", "140");
LevelCourse levelCourse = new LevelCourse("公共课");
levelCourse.addChild(chinese);
levelCourse.addChild(English);
levelCourse.addChild(Math);
levelCourse.info();
System.out.println("------------安全模式---------------------");
CommonSafeCourse history = new CommonSafeCourse("历史","120");
CommonSafeCourse politics = new CommonSafeCourse("历史","120");
CommonSafeCourse geography = new CommonSafeCourse("历史","120");
LevelSafeCourse levelSafeCourse = new LevelSafeCourse("文综", "360");
levelSafeCourse.addChild(history);
levelSafeCourse.addChild(politics);
levelSafeCourse.addChild(geography);
levelSafeCourse.info();
}
}
组合模式在源码中应用:
Map接口:HashMap putMapEntries 方法
场景分析:
组合模式一般的使用场景有:
- 处理一个树形结构,比如,公司人员组织架构、订单信息等;。跨越多个层次结构聚合数据,比如,统计文件夹下文件总数;
- 统一处理一个结构中的多个对象,比如,遍历文件夹下所有 XML类型文件内容。
为什么使用组合模式:
- 希望一组对象按照某种层级结构进行管理,比如,管理文件夹和文件,管理订单下的商品等。树形结构天然有一种层次的划分特性,能够让我们自然地理解多个对象间的结构。
- 需要按照统一的行为来处理复杂结构中的对象,比如,创建文件,删除文件,移动文件等。在使用文件时,我们其实并不关心文件夹和文件是如何被组织和存储的,只要我们能够正确操作文件即可,这时组合模式就能够很好地帮助我们组织复杂的结构,同时按照定义的统一行为进行操作,
- 能够快速扩展对象组合。比如,订单下的手机商品节点可以自由挂接不同分类的手机(品牌类的,如华为、苹果),并且还可以按照商品的特性(如,价格、图片、商家、功能等)再自由地挂接新的节点组合,而查找时可以从手机开始查找,不断增加节点类型,直到找到合适的手机商品。
组合模式优缺点 :
优点:
- 简化客户端代码:组合模式可以让客户端代码更简单,因为客户端不需要知道处理的是单个对象还是组合对象,可以统一使用相同的方式来处理它们。
- 增加新的构件更方便:使用组合模式可以很方便地增加新的构件,只需要实现抽象构件接口即可,不需要修改现有的代码。
- 灵活性好:组合模式可以让你灵活地组合对象,可以随意添加、删除或替换构件,而不会影响整个系统的稳定性。
- 易于扩展:组合模式可以很容易地扩展,可以在不修改现有代码的情况下增加新的行为。
缺点:
- 可能会导致设计过度复杂:如果组合模式的层次结构过于复杂,可能会导致设计过度复杂,使得代码难以理解和维护。
- 可能会降低系统性能:由于组合模式需要递归遍历整个树形结构,可能会降低系统的性能。如果组合模式的层次结构过于复杂,可能会导致性能下降更为明显。可能会增加系统的抽象性:组合模式需要使用抽象类或接口来定义抽象构件,可能会增加系统的抽象性,降低代码的可读性和可维护性。