组合模式
通过将单个对象和组合对象用相同的接口表示,使得客户端对单个对象和组合对象保存一致的处理,属于结构型模式。
使用场景
- 希望客户端可以忽略单个和整体对象的差异
- 对象层次具备整体和部分,通常成树形结构(公司的组织架构,操作系统的文件目录, 树形菜单等)
具体实现(2种)
主要是部分和整体实现公共的接口。
- 透明实现(部分与整体差异小,不经常变动),接口拥有所有方法,没有权限或调用功能直接抛出异常
- 安全实现(部分与整体差异较大),接口只有公共方法,各自有独立的方法
透明模式demo(对比安全模式,主要在接口定义上不一样)
package com.lovingmo.spdemo01.demo.compose;
public abstract class Directory {
public void show(){};
// 这个方法在File中用不上,但是会被继承或实现,调用抛出异常
public Directory add(Directory directory ){
throw new RuntimeException("添加异常");
}
}
安全模式demo
Directory.java
package com.lovingmo.spdemo01.demo.compose;
public abstract class Directory {
public void show(){};
}
File.java
package com.lovingmo.spdemo01.demo.compose;
public class File extends Directory{
private String name;
public File(String name) {
this.name = name;
}
@Override
public void show() {
System.out.println(this.name);
}
}
Folder.java
package com.lovingmo.spdemo01.demo.compose;
import java.util.ArrayList;
import java.util.List;
public class Folder extends Directory{
private List<Directory> directories;
private String name;
private Integer level;
public Folder(String name, int level) {
this.name = name;
this.level = level;
this.directories = new ArrayList<>();
}
public Directory add(Directory directory){
directories.add(directory);
return directory;
}
@Override
public void show() {
System.out.println(this.name);
for (Directory directory : directories){
if(this.level != null){
for (int a = 0; a< this.level; a++){
System.out.print(" ");
}
for(int i = 0; i < this.level; i ++){
//每一行开始打印一个+号
if(i == 0){ System.out.print("+"); }
System.out.print("-");
}
}
directory.show();
}
}
}
Test.java
package com.lovingmo.spdemo01.demo.compose;
public class Test {
public static void main(String[] args) {
File idea = new File("idea.exe");
File mysql = new File("mysql.exe");
Folder games = new Folder("游戏", 2);
File lol = new File("lol.exe");
File dnf = new File("dnf.exe");
games.add(lol);
games.add(dnf);
Folder root = new Folder("D:/", 1);
root.add(games);
root.add(idea);
root.add(mysql);
root.show();
}
}
源码中的使用
- HashMap中的put()与putAll()
- ArrayList中的add()与addAll()
优点
- 清楚的定义分层次的复杂对象,表示对象的全部和部分层次
- 让客户端忽略对层次的差异,方便对整个层次结构进行控制
- 简化客户端代码
- 符合开闭原则
缺点
- 限制类型时较为复杂
- 设计时更加抽象