this.score = score;
}
@Override
public String getName(){
return this.name;
}
@Override
public void info() {
System.out.println(“课程:” + this.name + “,分数:” + score);
}
}
3、建立一个具有层级的节点,三个方法都重写了,支持添加子节点,这个类里面为了方便打印的时候看出层级关系,所以我定义了一个层级属性。
package com.zwx.design.pattern.composite.transparency;
import java.util.ArrayList;
import java.util.List;
/**
- 树枝节点
*/
public class LevelCource extends GkAbstractCourse{
private List courseList = new ArrayList<>();
private String name;
private int level;
public LevelCource(String name, int level) {
this.name = name;
this.level = level;
}
@Override
public void addChild(GkAbstractCourse course) {
courseList.add(course);
}
@Override
public String getName(){
return this.name;
}
@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();
}
}
}
4、建立一个测试类来测试一下:
package com.zwx.design.pattern.composite.transparency;
public class TestTransparency {
public static void main(String[] args) throws Exception {
GkAbstractCourse ywCourse = new CommonCource(“语文”,“150”);
GkAbstractCourse sxCourse = new CommonCource(“数学”,“150”);
GkAbstractCourse yyCourse = new CommonCource(“英语”,“150”);
GkAbstractCourse wlCourse = new CommonCource(“物理”,“110”);
GkAbstractCourse hxCourse = new CommonCource(“化学”,“100”);
GkAbstractCourse swCourse = new CommonCource(“生物”,“90”);
GkAbstractCourse lzCourse = new LevelCource(“理综”,2);
lzCourse.addChild(wlCourse);
lzCourse.addChild(hxCourse);
lzCourse.addChild(swCourse);
GkAbstractCourse gkCourse = new LevelCource(“理科高考科目”,1);
gkCourse.addChild(ywCourse);
gkCourse.addChild(sxCourse);
gkCourse.addChild(yyCourse);
gkCourse.addChild(lzCourse);
gkCourse.info();
}
}
输出结果:
课程:理科高考科目
课程:语文,分数:150
课程:数学,分数:150
课程:英语,分数:150
课程:理综
课程:物理,分数:110
课程:化学,分数:100
课程:生物,分数:90
这里如果用普通科目去调用add方法就会抛出异常,假如上面调用:
swCourse.addChild(ywCourse);
会输出
不支持添加操作
因为在普通科目类里面并没有重写addChild方法。
透明模式的特点就是将组合对象所有的公共方法都定义在了抽象组件内,这样做的好处是客户端无需分辨当前对象是属于树枝节点还是叶子节点,因为它们具备了完全一致的接口,不过缺点就是叶子节点得到到了一些不属于它的方法,比如上面的addChild方法,这违背了接口隔离性原则。
《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
–
安全组合模式只是规定了系统各个层次的最基础的一致性行为,而把组合(树节点)本身的方法(如树枝节点管理子类的addChild等方法)放到自身当中。
1、首先还是建立一个顶层的抽象根节点(这里面只定义了一个通用的抽象info方法):
package com.zwx.design.pattern.composite.safe;
package com.zwx.design.pattern.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();
}
2、建立一个叶子节点(这里只是重写了info方法,没有定义其他特有方法):
package com.zwx.design.pattern.composite.safe;
/**
- 叶子节点
*/
public class CommonCource extends GkAbstractCourse {
public CommonCource(String name,String score) {
super(name,score);
}
@Override
public void info() {
System.out.println(“课程:” + this.name + “,分数:” + this.score);
}
}
3、定义一个树枝节点(这个类当中定义了一个树枝特有的方法addChild):
package com.zwx.design.pattern.composite.safe;
import java.util.ArrayList;
import java.util.List;
/**
- 树枝节点
*/
public class LevelCource extends GkAbstractCourse{
private List courseList = new ArrayList<>();
private int level;
public LevelCource(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();
}
}
}
4、新建测试类来测试:
package com.zwx.design.pattern.composite.safe;
public class TestSafe {
public static void main(String[] args) throws Exception {
CommonCource ywCourse = new CommonCource(“语文”,“150”);
CommonCource sxCourse = new CommonCource(“数学”,“150”);
CommonCource yyCourse = new CommonCource(“英语”,“150”);
CommonCource wlCourse = new CommonCource(“物理”,“110”);
CommonCource hxCourse = new CommonCource(“化学”,“100”);
CommonCource swCourse = new CommonCource(“生物”,“90”);
LevelCource lzCourse = new LevelCource(“理综”,“300”,2);
lzCourse.addChild(wlCourse);
lzCourse.addChild(hxCourse);
lzCourse.addChild(swCourse);
LevelCource gkCourse = new LevelCource(“理科高考”,“750”,1);
gkCourse.addChild(ywCourse);
gkCourse.addChild(sxCourse);
gkCourse.addChild(yyCourse);
gkCourse.addChild(lzCourse);
gkCourse.info();
}
}
输出结果为:
课程:理科高考,分数:750
课程:语文,分数:150
课程:数学,分数:150
课程:英语,分数:150
课程:理综,分数:300
课程:物理,分数:110
课程:化学,分数:100
课程:生物,分数:90
这里和透明方式不一样,叶子节点不具备addChild功能,所以无法调用,而上面的示例中时可以被调用,但是调用之后显示不支持,这就是这两种写法最大的区别。
===================================================================
从上面示例中,可以看到组合模式包含了以下三个角色:
-
抽象根节点(Component):定义系统各层次对象的公有属性和方法,可以预先定义一些默认行为和属性。
-
树枝节点(Composite):定义树枝节点的行为,存储子节点,组合树枝节点和叶子节点形成一个树形结构。
-
叶子节点(Leaf):是系统遍历层次中的最小单位,下面没有子节点。
===========================================================================
- 1、HashMap
HashMap中有一个putAll方法,参数是一个Map,这就是一种组合模式的体现:
另外还有ArrayList中的addAll方法也是一样。
- 2、MyBatis中有一个SqlNode接口,下面很多一级标签:
然后一级标签下面又有二级标签(这就是组合模式的体现):
=====================================================================
组合模式一般应用在有层级关系的场景,最经典的就是树形菜单,文件和文件夹的管理等
====================================================================