一、组合模式
1、定义
组合模式(Composite Pattern)又称作整体-部分(Part-Whole)模式
,其宗旨是通过将单个对象(叶子节点)和组织对象(树枝节点)用相同的接口进行表示,使得客户对单个对象和组合对象的使用具有一致性,属于结构型设计模式。
2、结构
(1)模式的结构
主要角色如下:
- 抽象组成角色(Component):单个对象和组织对象的抽象基类或者接口,表示整个树形结构中的对象都属于同一种类型,用于访问和管理子节点。
- 组织对象角色(Composite):树枝节点,用来存储子节点,并实现了组织接口中的操作方法。
- 单个对象角色(Left):叶子节点,它没有子节点,它不需要实现组织接口中的操作方法。
(2)组合模式有两种
透明组合模式:
组织接口中声明用来管理子对象的所有行为方法,好处就是树枝节点和叶子节点对外界没有区别,它们具备完全一致的行为接口,缺点时,叶子节点本身不具备组织接口的行为方法,所以实现它们是没有意义的。安全组合模式:
组织接口中不声明用来管理子对象的所有行为方法,所以叶子节点也就不需要去实现它们。而是在组织节点中声明用来管理子对象的所有行为方法。这样做由于不够透明,树枝节点和叶子节点将不具有相同的接口,客户端的调用需要做相应的判断,带来了不便。
3、优缺点
优点:
- 清楚地定义各层次的复杂对象,表示对象的全部或部分层次。
- 让客户端忽略了层次的差异,方便对整个层次结构进行控制。
- 符合开闭原则。
缺点:
- 限制类型时会较为复杂。
- 使设计变得更加抽象。
4、使用场景
- 希望客户端可以忽略组个对象与单个对象的差异。
- 对象层次具备整体和部分,呈树形结构。
5、在框架源码中使用
- Java中 HashMap 的 putAll方法,存储使用了一个静态内部类的数据Node[]。
- Mybatis源码中解析Mapping文件中的 SQL语句时,使用到的 SqlNode类的作用非常关键。
二、模式的通用实现
1、透明组合模式
代码如下:
public class CompositePattern1 {
public static void main(String[] args) {
Component1 root = new Composite1("root");
Component1 branch1 = new Composite1("branch1");
Component1 branch2 = new Composite1("branch2");
Component1 leaf1 = new Leaf1("leaf1");
Component1 leaf2 = new Leaf1("leaf2");
Component1 leaf3 = new Leaf1("leaf3");
Component1 leaf4 = new Leaf1("leaf4");
root.addChild(branch1);
root.addChild(leaf3);
branch1.addChild(leaf1);
branch1.addChild(branch2);
branch2.addChild(leaf2);
branch2.addChild(leaf4);
String display = root.display();
System.out.println(display);
System.out.println("===============");
System.out.println("branch2.getChild(1).display() -> " + branch2.getChild(1).display());
branch2.removeChild(leaf4);
String display2 = root.display();
System.out.println(display2);
}
}
// 抽象组成角色
abstract class Component1 {
protected String name;
public Component1(String name) {
this.name = name;
}
public abstract String display();
public boolean addChild(Component1 component1) {
throw new RuntimeException(" addChild 不支持");
}
public boolean removeChild(Component1 component1) {
throw new RuntimeException(" removeChild 不支持");
}
public Component1 getChild(int index) {
throw new RuntimeException(" getChild 不支持");
}
}
// 组织对象角色
class Composite1 extends Component1 {
private List<Component1> component1List;
public Composite1(String name) {
super(name);
this.component1List = new ArrayList<Component1>();
}
@Override
public String display() {
StringBuilder sb = new StringBuilder(this.name);
for (int i = 0; i < component1List.size(); i++) {
Component1 component1 = component1List.get(i);
sb.append("\n");
sb.append(component1.display());
}
return sb.toString();
}
@Override
public boolean addChild(Component1 component1) {
return component1List.add(component1);
}
@Override
public boolean removeChild(Component1 component1) {
return component1List.remove(component1);
}
@Override
public Component1 getChild(int index) {
return component1List.get(index);
}
}
// 单个对象角色
class Leaf1 extends Component1 {
public Leaf1(String name) {
super(name);
}
@Override
public String display() {
return this.name;
}
}
2、安全组合模式
代码如下:
public class CompositePattern2 {
public static void main(String[] args) {
Composite2 root = new Composite2("root");
Composite2 branch1 = new Composite2("branch1");
Composite2 branch2 = new Composite2("branch2");
Component2 leaf1 = new Leaf2("leaf1");
Component2 leaf2 = new Leaf2("leaf2");
Component2 leaf3 = new Leaf2("leaf3");
Component2 leaf4 = new Leaf2("leaf4");
root.addChild(branch1);
root.addChild(leaf3);
branch1.addChild(leaf1);
branch1.addChild(branch2);
branch2.addChild(leaf2);
branch2.addChild(leaf4);
String display = root.display();
System.out.println(display);
System.out.println("===============");
System.out.println("branch2.getChild(1).display() -> " + branch2.getChild(1).display());
branch2.removeChild(leaf4);
String display2 = root.display();
System.out.println(display2);
}
}
// 抽象组成角色
abstract class Component2 {
protected String name;
public Component2(String name) {
this.name = name;
}
public abstract String display();
}
// 组织对象角色
class Composite2 extends Component2 {
private List<Component2> component2List;
public Composite2(String name) {
super(name);
this.component2List = new ArrayList<Component2>();
}
@Override
public String display() {
StringBuilder sb = new StringBuilder(this.name);
for (int i = 0; i < component2List.size(); i++) {
sb.append("\n");
Component2 component2 = component2List.get(i);
sb.append(component2.display());
}
return sb.toString();
}
public boolean addChild(Component2 component2) {
return component2List.add(component2);
}
public boolean removeChild(Component2 component2) {
return component2List.remove(component2);
}
public Component2 getChild(int index) {
return component2List.get(index);
}
}
// 单个对象角色
class Leaf2 extends Component2 {
public Leaf2(String name) {
super(name);
}
@Override
public String display() {
return this.name;
}
}
三、模式的应用实例
以文件系统为例,目录包含文件夹和文件。下面使用安全组合模式实现。
(1)目录:抽象组成角色
public abstract class Directory {
protected String name;
public Directory(String name) {
this.name = name;
}
public abstract void show();
}
(2)文件夹:组织对象角色
public class Folder extends Directory {
private List<Directory> dirList;
private Integer depth;
public Folder(String name, Integer depth) {
super(name);
this.depth = depth;
dirList = new ArrayList<>();
}
public void list() {
for (Directory dir : this.dirList) {
System.out.println(dir.name);
}
}
@Override
public void show() {
System.out.println(this.name);
for (Directory dir : this.dirList) {
if (this.depth != null) {
for (Integer integer = 0; integer < this.depth; integer++) {
System.out.print(" ");
}
for (Integer integer = 0; integer < this.depth; integer++) {
if (integer == 0) {
System.out.print("+");
}
System.out.print("-");
}
}
dir.show();
}
}
public boolean addChild(Directory directory) {
return dirList.add(directory);
}
public boolean removeChild(Directory directory) {
return dirList.remove(directory);
}
public Directory getChild(int index) {
return dirList.get(index);
}
}
(3)文件:单个对象角色
public class File extends Directory{
public File(String name) {
super(name);
}
@Override
public void show() {
System.out.println(this.name);
}
}
(4)测试
public static void main(String[] args) {
Folder root = new Folder("root", 1);
File dy = new File("抖音.exe");
File qq = new File("QQ.exe");
root.addChild(dy);
root.addChild(qq);
Folder office = new Folder("办公软件", 2);
File word = new File("Word.exe");
File ppt = new File("PPT.exe");
File excel = new File("Excel.exe");
office.addChild(word);
office.addChild(ppt);
office.addChild(excel);
Folder devTools = new Folder("开发工具", 3);
File idea = new File("idea.exe");
File navicat = new File("navicat.exe");
devTools.addChild(idea);
devTools.addChild(navicat);
office.addChild(devTools);
root.addChild(office);
System.out.println("========show方法======");
root.show();
System.out.println("========list方法======");
root.list();
}
– 求知若饥,虚心若愚。