定义:
结构型组合模式(Composite Pattern) 它的宗旨是通过将单个对象和组合对象用相同的接口进行表示,使客户端对单个对象和组合对象保持一致的方式处理。
心在一起叫团队,人在一起叫团伙。团伙是聚合,团队是组合。组合有生命周期, 而聚合就像U盘与电脑, 就算分开也能单独使用。
适用场景:
1.希望客户端可以忽略组合对象与单个对象的差异时。
2.对象层次具备整体和部分,呈树形结构。如树形菜单,操作系统目录结构,公司组织架构等。
优点:
1.清楚的定义分层次的复杂对象,表示对象的全部或部分层次。
2.让客户端忽略了层次的差异,方便对整个层次结构进行控制。
3.简化客户端代码。
4.符合开闭原则。
缺点:
1.限制类型时会较为复杂,如果做一些特殊处理则需要定义其它函数解决。
2.使设计变的更复杂,因为需要找到共性与差异。
示例:
/**
* 透明模式
* 抽象组件,可以是接口和抽象类:以课程为例
*/
public class CourseComponet {
public void addChild(CourseComponet componet){
throw new UnsupportedOperationException("不支持添加");
}
public void removeChild(CourseComponet componet){
throw new UnsupportedOperationException("不支持删除");
}
public String getName(CourseComponet componet){ throw new UnsupportedOperationException("不支持获取名称"); }
public double getPrice(CourseComponet componet){ throw new UnsupportedOperationException("不支持获取价格"); }
public void print(){
throw new UnsupportedOperationException("不支持打印");
}
}
/**
* 课程目录.目录节点
*/
public class CourseCategory extends CourseComponet {
// 不管有多少层级,最终的根节点都属于CourseComponet
private List<CourseComponet> items = new ArrayList<>();
private String name;
private Integer level; // 等级
CourseCategory(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(CourseComponet componet){
return this.name;
}
@Override
public void print(){
// 打印成类似树形结构
System.out.println(name);
for (CourseComponet item : items){
if(level != null){
for(int i = 0; i < level; i++){
System.out.print(" ");
}
for(int i = 0; i < level; i++){
if(i == 0){
System.out.print("+");
}
System.out.print("-");
}
}
item.print();
}
}
}
**
* 具体课程.叶子节点
*/
public class Course extends CourseComponet{
private final static Logger logger = Logger.getLogger(Course.class);
private String name;
private double price;
Course(String name,double price){
this.name = name;
this.price = price;
}
@Override
public String getName(CourseComponet componet){
return this.name;
}
@Override
public double getPrice(CourseComponet componet){
return this.price;
}
public void print(){
System.out.println("书籍:" + name + ", 售价:" + price + "RMB");
}
}
// 模拟客户端
public class MainExcute {
private final static Logger logger = Logger.getLogger(MainExcute.class);
public static void main(String[] args) {
logger.info("=============透明模式==============");
// 类目
CourseComponet category = new CourseCategory("课程类目",1);
CourseComponet courseCategory = new CourseCategory("系统架构",2);
// 课程
CourseComponet design = new Course("设计模式",2000);
CourseComponet source = new Course("源码剖析",3800);
CourseComponet softSkill = new Course("软技能",3500);
CourseComponet cLanguage = new Course("C语言",3880);
CourseComponet ai = new Course("人工智能",5200);
courseCategory.addChild(design);
courseCategory.addChild(source);
courseCategory.addChild(softSkill);
category.addChild(cLanguage);
category.addChild(ai);
category.addChild(courseCategory);
category.print();
// 当子节点添加子节点会出现错误,衍生出安全模式写法。
// ai.addChild(design);
}
}
====================================
/**
* 安全模式
* 抽象组件,可以是接口和抽象类:以系统文件结构为例
*/
public abstract class Direcotry {
public String name;
Direcotry(String name){
this.name = name;
}
public abstract void show();
}
/**
* 文件夹节点
*/
public class Folder extends Direcotry{
// 需要一个容器保存所有的文件
List<Direcotry> dirs;
private Integer level; // 层级标识
Folder(String name,Integer level) {
super(name);
this.level = level;
dirs = new ArrayList<>();
}
@Override
public void show() {
// 打印成类似树形结构
System.out.println(this.name);
for (Direcotry dir : dirs){
if(level != null){
for(int i = 0; i < level; i++){
System.out.print(" ");
}
for(int i = 0; i < level; i++){
if(i == 0){
System.out.print("+");
}
System.out.print("-");
}
}
dir.show();
}
}
public boolean add(Direcotry dir){
return dirs.add(dir);
}
public boolean remove(Direcotry dir){
return dirs.remove(dir);
}
public Direcotry get(int index){
return dirs.get(index);
}
/**
* 当前目录下的文件
*/
public void list(){
for (Direcotry dir : dirs){
System.out.println(dir.name);
}
}
}
/**
* 文件节点
*/
public class File extends Direcotry{
File(String name){
super(name);
}
@Override
public void show() {
System.out.println(this.name);
}
}
// 模拟客户端
public class MainExcute {
private final static Logger logger = Logger.getLogger(MainExcute.class);
public static void main(String[] args) {
logger.info("=============安全模式==============");
// 目录
Folder root = new Folder("D盘",1);
Folder office = new Folder("办公软件",2);
// 文件
File word = new File("Word.exe");
File ppt = new File("PowerPoint.exe");
File excel = new File("Excel.exe");
File qq = new File("QQ.exe");
File wx = new File("微信.exe");
office.add(word);
office.add(ppt);
office.add(excel);
root.add(qq);
root.add(wx);
root.add(office);
root.show();
root.list();
/**
* 饰器在源码中的应用
* HashMap.putAll(Map<? extends K, ? extends V> m)
* Map的抽象组件是Entry,Map中放Map,这不就是组合嘛。
* ArrayList.addAll 同理
*/
}
}
类图:
1.透明模式
2.安全模式