组合模式:Composite, 将对象组合成树形结构以表示“部分-整体”的层次机构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
简而言之组合模式
- 组合模式主要是为了解决树形结构枝节点与叶节点的使用一致性问题。
- 组合模式分为安全组合模式与透明组合模式。
模式结构的角色类:
- Component: 抽象构件,抽象类或接口,定义叶子节点与枝节点共同的方法。
- Composite: 枝节点,用来维护子节点对象集合。
- leaf: 叶子节点,末端节点。
安全组合模式:Component构件中定义所有除了对于子节点组合关系维护的方法以外的方法。
缺点:
此时由于枝节点中自身维护子节点集合的方法,从而在使用组合模式是需要区分枝节点与叶子节点。
透明组合模式:Component构件中定义所有方法,特别是对于子节点组合关系维护的方法。
缺点:
与安全模式相反的的是,叶子节点中也继承了子节点关系维护的方法,当叶子节点这些方法被调用时,就会出现错误。
TranslateComponent.java
package com.frank.designMode.CompositeMode.demo.translateDemo;
/**
* @Description: 透明模式- 定义公共方法与属性, 此组件可以为接口或抽象类
* @Author: Frank.Liu
* @Date:25/05/2020
*/
public abstract class TranslateComponent {
protected String name;
public TranslateComponent(String name){
this.name = name;
}
public abstract boolean add(TranslateComponent component) throws Exception;
public abstract boolean reomve(TranslateComponent component) throws Exception;
public abstract void display(int depth);
}
TranslateComposite.java
package com.frank.designMode.CompositeMode.demo.translateDemo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @Description: 透明模式- 中间组件,含有子节点。
* @Author: Frank.Liu
* @Date:25/05/2020
*/
public class TranslateComposite extends TranslateComponent {
private List<TranslateComponent> childrenList = new ArrayList<>();
public TranslateComposite(String name) {
super(name);
}
@Override
public boolean add(TranslateComponent component) throws Exception {
return childrenList.add(component);
}
@Override
public boolean reomve(TranslateComponent component) throws Exception {
return childrenList.remove(component);
}
@Override
public void display(int depth) {
System.out.println(String.format( String.join("-", Collections.nCopies(depth, ""))+this.name));
for (TranslateComponent child:childrenList) {
child.display(depth+2);
}
}
}
Leaf.java
package com.frank.designMode.CompositeMode.demo.translateDemo;
import java.util.Collections;
/**
* @Description: 叶子节点,终端节点
* @Author: Frank.Liu
* @Date:25/05/2020
*/
public class Leaf extends TranslateComponent {
String resultMsg = "Throw Exception which can't support this method.";
public Leaf(String name) {
super(name);
}
@Override
public boolean add(TranslateComponent component) throws Exception{
// 叶子节点不能增加子节点,抛出异常。
throw new RuntimeException(resultMsg);
}
@Override
public boolean reomve(TranslateComponent component) throws Exception{
// 叶子节点不能增加子节点,抛出异常。
throw new RuntimeException(resultMsg);
}
@Override
public void display(int depth) {
System.out.println(String.format( String.join("-", Collections.nCopies(depth, ""))+this.name));
}
}
Client.java
package com.frank.designMode.CompositeMode.demo.translateDemo;
public class Client {
public static void main(String[] args) {
// 透明模式
try {
TranslateComponent root = new TranslateComposite("root");
Leaf leve1_leaf_A = new Leaf("leve1-leaf_A");
Leaf leve1_leaf_B = new Leaf("leve1-leaf_B");
root.add(leve1_leaf_A);
root.add(leve1_leaf_B);
TranslateComponent leve1_A = new TranslateComposite("leve1-A");
Leaf leve1_A_leaf_A = new Leaf("leve1-A-leaf_A");
Leaf leve1_A_leaf_B = new Leaf("leve1-A-leaf_B");
leve1_A.add(leve1_A_leaf_A);
leve1_A.add(leve1_A_leaf_B);
root.add(leve1_A);
TranslateComponent leve1_B = new TranslateComposite("leve1-B");
Leaf leve1_B_leaf_A = new Leaf("leve1-B-leaf_A");
Leaf leve1_B_leaf_B = new Leaf("leve1-B-leaf_B");
leve1_B.add(leve1_B_leaf_A);
leve1_B.add(leve1_B_leaf_B);
root.add(leve1_B);
root.display(1);
System.out.println("=================remove TranslateComposite==================");
root.reomve(leve1_A);
root.display(1);
} catch (Exception e) {
e.printStackTrace();
}
//安全模式
}
}
SafeComponent.java
package com.frank.designMode.CompositeMode.demo.safeDemo;
/**
* @Description: 安全模式- 定义公共方法与属性, 此组件可以为接口或抽象类
* @Author: Frank.Liu
* @Date:25/05/2020
*/
public abstract class SafeComponent {
protected String name;
public SafeComponent(String name){
this.name = name;
}
public abstract void display(int depth);
}
SafeComposite.java
package com.frank.designMode.CompositeMode.demo.safeDemo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @Description: 透明模式- 中间组件,含有子节点。
* @Author: Frank.Liu
* @Date:25/05/2020
*/
public class SafeComposite extends SafeComponent {
private List<SafeComponent> childrenList = new ArrayList<>();
public SafeComposite(String name) {
super(name);
}
public boolean add(SafeComponent component) throws Exception {
return childrenList.add(component);
}
public boolean reomve(SafeComponent component) throws Exception {
return childrenList.remove(component);
}
@Override
public void display(int depth) {
System.out.println(String.format( String.join("-", Collections.nCopies(depth, ""))+this.name));
for (SafeComponent child:childrenList) {
child.display(depth+2);
}
}
}
SafeLeaf.java
package com.frank.designMode.CompositeMode.demo.safeDemo;
import java.util.Collections;
/**
* @Description: 叶子节点,终端节点
* @Author: Frank.Liu
* @Date:25/05/2020
*/
public class SafeLeaf extends SafeComponent {
String resultMsg = "Throw Exception which can't support this method.";
public SafeLeaf(String name) {
super(name);
}
@Override
public void display(int depth) {
System.out.println(String.format( String.join("-", Collections.nCopies(depth, ""))+this.name));
}
}
Client.java
package com.frank.designMode.CompositeMode.demo.translateDemo;
public class Client {
public static void main(String[] args) {
// 透明模式
try {
TranslateComponent root = new TranslateComposite("root");
Leaf leve1_leaf_A = new Leaf("leve1-leaf_A");
Leaf leve1_leaf_B = new Leaf("leve1-leaf_B");
root.add(leve1_leaf_A);
root.add(leve1_leaf_B);
TranslateComponent leve1_A = new TranslateComposite("leve1-A");
Leaf leve1_A_leaf_A = new Leaf("leve1-A-leaf_A");
Leaf leve1_A_leaf_B = new Leaf("leve1-A-leaf_B");
leve1_A.add(leve1_A_leaf_A);
leve1_A.add(leve1_A_leaf_B);
root.add(leve1_A);
TranslateComponent leve1_B = new TranslateComposite("leve1-B");
Leaf leve1_B_leaf_A = new Leaf("leve1-B-leaf_A");
Leaf leve1_B_leaf_B = new Leaf("leve1-B-leaf_B");
leve1_B.add(leve1_B_leaf_A);
leve1_B.add(leve1_B_leaf_B);
root.add(leve1_B);
root.display(1);
System.out.println("=================remove TranslateComposite==================");
root.reomve(leve1_A);
root.display(1);
} catch (Exception e) {
e.printStackTrace();
}
//安全模式
}
}
FolderComponent.java
package com.frank.designMode.CompositeMode.demo.example;
/**
* @Description: 文件对象与文件夹对象抽象类
* @Author: Frank.Liu
* @Date:25/05/2020
*/
public abstract class FolderComponent {
protected String fileName;
public FolderComponent(String fileName){
this.fileName = fileName;
}
public abstract void addFile(FolderComponent component) throws Exception;
public abstract void removeFile(FolderComponent component) throws Exception;
public abstract void display(int depth);
}
ConcreteFolder.java
package com.frank.designMode.CompositeMode.demo.example;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @Description: 文件夹对象抽象类
* @Author: Frank.Liu
* @Date:25/05/2020
*/
public class ConcreteFolder extends FolderComponent{
private List<FolderComponent> childrenList = new ArrayList<>();
public ConcreteFolder(String fileName) {
super(fileName);
}
@Override
public void addFile(FolderComponent component) throws Exception {
childrenList.add(component);
}
@Override
public void removeFile(FolderComponent component) throws Exception {
childrenList.remove(component);
}
@Override
public void display(int depth) {
System.out.println(String.format( String.join("-", Collections.nCopies(depth, ""))+this.fileName));
for (FolderComponent child:childrenList) {
child.display(depth+2);
}
}
}
FileLeaf.java
package com.frank.designMode.CompositeMode.demo.example;
import java.util.Collections;
/**
* @Description: 叶子节点,具体文件类
* @Author: Frank.Liu
* @Date:25/05/2020
*/
public class FileLeaf extends FolderComponent{
String resultMsg = "Throw Exception which can't support this method.";
public FileLeaf(String fileName) {
super(fileName);
}
@Override
public void addFile(FolderComponent component) throws Exception {
}
@Override
public void removeFile(FolderComponent component) throws Exception {
}
@Override
public void display(int depth) {
System.out.println(String.format( String.join("-", Collections.nCopies(depth, ""))+this.fileName));
}
}
Client.java
package com.frank.designMode.CompositeMode.demo.example;
public class Client {
public static void main(String[] args) {
// 透明模式
try {
FolderComponent rootFolder = new ConcreteFolder("FolderRoot");
FolderComponent fileA = new FileLeaf("fileA");
FolderComponent fileB = new FileLeaf("fileB");
rootFolder.addFile(fileA);
rootFolder.addFile(fileB);
FolderComponent folderA = new ConcreteFolder("FolderA");
FolderComponent fileC = new FileLeaf("fileC");
FolderComponent fileD = new FileLeaf("fileD");
folderA.addFile(fileC);
folderA.addFile(fileD);
rootFolder.addFile(folderA);
FolderComponent folderB = new ConcreteFolder("FolderB");
FolderComponent fileE = new FileLeaf("fileE");
FolderComponent fileF = new FileLeaf("fileF");
folderB.addFile(fileE);
folderB.addFile(fileF);
rootFolder.addFile(folderB);
rootFolder.display(1);
} catch (Exception e) {
e.printStackTrace();
}
//安全模式
}
}
- 在具有整体和部分的层次结构中,希望通忽略整体与部分的差异从而一致性的对待。
- 功能中需要树形结构。
- 解耦叶子对象和容器对象,而且它们的类型不固定,动态增加新类型。
- 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
- 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
- 在组合模式中增加新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改,符合“开闭原则”。
- 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。
- 使得设计更加复杂,客户端需要花更多时间理清类之间的层次关系。
- 在增加新构件时很难对容器中的构件类型进行限制。