每个人出生的时候都是原创,可悲的是很多人渐渐都成了盗版。
俗话说:男女搭配,干活不累!这句话讲究的是合适的组合,能使效果更好。代码世界中同样存在这样的模式——组合模式
1. 组合模式
定义
也称为整体部分模式,宗旨是通过将单个对象(叶子节点)和组合对象(树枝节点)用相同的接口进行表示
作用:使客户端对单个对象和组合对象保持一致的方式处理
属于结构型模式
优点
清楚地定义分层次的复杂对象,表示对象的全部或者部分层次
让客户端忽略了层次的差异,方便对整个层次接口进行控制
简化客户端代码
符合开闭原则
缺点
限制类型时会较为复杂
使设计变得更加抽象
2. 透明组合模式
举个例子:大学期间,一共上四年,四年中每年学的课程都不一样。四年中每年的课程组合形成了我们大学的整个课程体系,那么问题来了,我们怎么设计这种组合模式来层级输出大学四年每年的课程呢?
public abstract class CourseComponet {
public void addChild(CourseComponet componet) {
throw new UnsupportedOperationException("不支持添加操作");
}
public void removeChild(CourseComponet componet) {
throw new UnsupportedOperationException("不支持删除操作");
}
public String getName() {
throw new UnsupportedOperationException("不支持获取名称操作");
}
public double getPrice() {
throw new UnsupportedOperationException("不支持获取价格操作");
}
public void print() {
throw new UnsupportedOperationException("不支持打印操作");
}
}
public class Course extends CourseComponet {
private String name;
private double price;
public Course(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String getName() {
return this.name;
}
@Override
public double getPrice() {
return this.price;
}
@Override
public void print() {
System.out.println(name + ":" + price + "元");
}
}
public class CoursePackage extends CourseComponet {
private List<CourseComponet> items = new ArrayList<CourseComponet>();
private String name;
private Integer level;
public CoursePackage(String name, Integer level) {
this.name = name;
this.level = level;
}
@Override
public void addChild(CourseComponet componet) {
items.add(componet);
}
@Override
public void removeChild(CourseComponet componet) {
items.remove(componet);
}
@Override
public String getName() {
return this.name;
}
@Override
public void print() {
System.out.println(this.name);
for (CourseComponet c : items) {
if (this.level != null) {
for (int i = 0; i < this.level; i++) {
System.out.print(" ");
}
for (int i = 0; i < this.level; i++) {
if (i == 0) {
System.out.print("+");
}
System.out.print("-");
}
}
c.print();
}
}
}
public class Test {
public static void main(String[] args) {
System.out.println("=============透明的组合模式==============");
CourseComponet pd = new Course("程序设计基础", 84);
CourseComponet wjf = new Course("微积分", 130);
CourseComponet wl = new Course("物理", 76);
CourseComponet firstYear = new CoursePackage("第一年课程", 2);
firstYear.addChild(pd);
firstYear.addChild(wjf);
firstYear.addChild(wl);
CourseComponet gll = new Course("概率论", 34);
CourseComponet sxzz = new Course("思想政治", 45);
CourseComponet javaCourse = new Course("Java高级程序设计", 203);
CourseComponet secondYear = new CoursePackage("第二年课程", 3);
secondYear.addChild(gll);
secondYear.addChild(sxzz);
secondYear.addChild(javaCourse);
CourseComponet sf = new Course("算法", 302);
CourseComponet js = new Course("JavaScript", 280);
CourseComponet thirdYear = new CoursePackage("第三年课程", 4);
thirdYear.addChild(sf);
thirdYear.addChild(js);
CourseComponet sy = new Course("嵌入式实验", 56);
CourseComponet lw = new Course("毕业论文", 500);
CourseComponet firthYear = new CoursePackage("第四年课程", 5);
firthYear.addChild(sy);
firthYear.addChild(lw);
CourseComponet daxue = new CoursePackage("大学课程", 1);
daxue.addChild(firstYear);
daxue.addChild(secondYear);
daxue.addChild(thirdYear);
daxue.addChild(firthYear);
daxue.print();
}
}
=============透明的组合模式==============
大学课程
+-第一年课程
+--程序设计基础:84.0元
+--微积分:130.0元
+--物理:76.0元
+-第二年课程
+---概率论:34.0元
+---思想政治:45.0元
+---Java高级程序设计:203.0元
+-第三年课程
+----算法:302.0元
+----JavaScript:280.0元
+-第四年课程
+-----嵌入式实验:56.0元
+-----毕业论文:500.0元
首先定义一个课程组合抽象类,这个类中定义了所有方法,另外定义一个课程类继承这个抽象类,课程有的方法就是定义名字和书本价格,打印名字和价格,所以要重写父类的这三个方法,在定义一个课程包,也继承课程组合抽象类,课程包是什么?是存储课程的集合,和这个包的名字,还有这个包所在的级别。那么自然的他就有添加课程,删除课程,打印课程名字,获取课程包名字的方法,这些方法就需要重写。那么整个大学四年的课程,就可以分类装进对应的包中,最后把包装进大学四年课程这个包中,组成一棵树形结构打印。这就是组合模式。
但是这种写法存在问题,由于课程类没有重写添加和删除接口,那边课程再调用方法的时候是报错的,这是不安全的写法。
CourseComponet wjf = new Course("微积分", 130);
CourseComponet wl = new Course("物理", 76);
wl.addChild(wjf);
3. 安全组合模式
举个例子:典型的磁盘目录结构
public abstract class Direcotry {
protected String name;
public Direcotry(String name) {
this.name = name;
}
public abstract void show();
}
public class Folder extends Direcotry {
private List<Direcotry> dirs;
private Integer level;
public Folder(String name, Integer level) {
super(name);
this.level = level;
this.dirs = new ArrayList<Direcotry>();
}
@Override
public void show() {
System.out.println(this.name);
for (Direcotry c : dirs) {
if (this.level != null) {
for (int i = 0; i < this.level; i++) {
System.out.print(" ");
}
for (int i = 0; i < this.level; i++) {
if (i == 0) {
System.out.print("+");
}
System.out.print("-");
}
}
c.show();
}
}
public boolean add(Direcotry dir) {
return this.dirs.add(dir);
}
public boolean remove(Direcotry dir) {
return this.dirs.remove(dir);
}
public Direcotry get(int index) {
return this.dirs.get(index);
}
}
public class File extends Direcotry {
public File(String name) {
super(name);
}
@Override
public void show() {
System.out.println(this.name);
}
}
public class Test {
public static void main(String[] args) {
System.out.println("=============安全的组合模式==============");
File qq = new File("QQ.exe");
File wx = new File("WX.exe");
Folder office = new Folder("办公软件", 2);
File word = new File("word.exe");
File ppt = new File("ppt.exe");
office.add(word);
office.add(ppt);
Folder dir = new Folder("D盘:", 1);
dir.add(qq);
dir.add(wx);
dir.add(office);
dir.show();
}
}
=============安全的组合模式==============
D盘:
+-QQ.exe
+-WX.exe
+-办公软件
+--word.exe
+--ppt.exe
如果这时候,我想查看目录中有什么文件?这时候只需要扩展Folder
方法就行。
public void list() {
for (Direcotry dir : dirs) {
System.out.println(dir.name);
}
}
这时候,File
是没有list()
方法的,这就是安全模式。
感谢您阅读本文,如果您觉得文章写的对您有用的话,请您点击上面的“关注”,点个赞,这样您就可以持续收到《JAVA架构师之路》的最新文章了。文章内容属于自己的一点点心得,难免有不对的地方,欢迎在下方评论区探讨,你们的关注是我创作优质文章的动力。