重学设计模式(三、设计模式-组合模式)

142 阅读4分钟

1、组合模式

​ 前面我们学习设计原则的时候,讲过代码的扩展方式有继承和组合。今天我们要将的组合模式和组合方式是两个不同的概念。

1.1、什么是组合模式

  • 定义

组合模式: 是一种结构型设计模式,有时也叫合成模式。它允许您将对象组合成树结构,用来表示“整体-部分”的关系,从而使客户端可以使用统一的方式处理部分对象和整体对象(这些对象具体一致的访问性)。

​ 什么意思呢?就是当我们的应用程序的核心模型可以表示为树时,用组合模式才有意义。比如,大多数国家的军队都是按等级划分的,一支军队由几个师组成、一个师是一组旅、...一个连由排组成,排可以分解为班;最后,一个班是一小群真正的士兵,命令在层次结构的顶部下达,并传递到每个级别,直到每个士兵都知道需要做什么。

组合模式的意图在于:为了保证客户端用单个对象与组合对象的一致性。

​ 组合模式的核心角色:

​ 抽象构件(Component)角色:定义了叶子构件和容器构件的公共特点,即声明公共接口。

​ 叶子构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。

​ 容器构件(Composite)角色:有容器的特征,可以包含子节点,主要作用是存储和管理子部件,通常包含 add()、remove()、getChild() 等方法。

​ 在组合模式中,整个树形结构中的对象都属于同一种类型,最大好处是您不需要关心构成树的对象的具体类(不需要辨别是容器构件(分支节点)还是叶子节点)对象本身会将请求向下传递到树中,给用户的使用带来极大的便利。

1.2、组合模式的优缺点

  • 优点

​ 1)客户端可以更方便(一致地处理)的使用复杂的树结构,这简化了客户端代码;

​ 2)满足“开闭原则”,可以在不破坏现有代码的情况下将新元素类型引入应用程序;

​ 3)可以使用多态性和递归性来完成相应的功能。

  • 缺点

​ 1)为功能差异太大的类提供通用接口可能很困难。在某些情况下,您需要过度概括组件接口,使其更难理解;

​ 2)叶子构件都是实现类,而不是接口,违反了依赖倒置原则。

1.3、创建方式

​ 我们有杀毒软件查杀文件为例:

1)定义抽象构件

/**
 * 抽象构件
 * 杀毒软件-杀毒
 */
public interface IkillAirusFile {
    void killVirvs()//杀毒
}

2)定义叶子构件ImageFile、TextFile

//叶子构件
class ImageFile implements IkillAirusFile{
 private String name;
 
 public ImageFile(String name) {
  this.name = name;
 }
 
 @Override
 public void killVirvs() {
  System.out.println("查杀-图像文件:"+name);
 }
}
//叶子构件
class TextFile implements IkillAirusFile{
 private String name;
 
 public TextFile(String name) {
  this.name = name;
 }
 
 @Override
 public void killVirvs() {
  System.out.println("查杀-文本文件:"+name);
 }
}

3)定义容器构件Folder

//容器构件
public class Folder implements IkillAirusFile{

 private String name;
 //定义容器,用来存放容器下的叶子构件
 private List<IkillAirusFile> list = new ArrayList<IkillAirusFile>();
 
 public Folder(String name) {
  this.name = name;
 }
 
 public void add(IkillAirusFile file){
  list.add(file);
 }
 
 public void remove(IkillAirusFile file){
  list.remove(file);
 }
 
 public IkillAirusFile getChild(int index){
  return list.get(index);
 }
 
 @Override
 public void killVirvs( ) {
  System.out.println("查杀-文件夹:"+name);
  //递归查杀
  for (IkillAirusFile file : list) {
   file.killVirvs();
  }
 }
}

4)客户端调用

public class Client {

 public static void main(String[] args) {
  IkillAirusFile f1,f2,f3; //查杀文件
  Folder D = new Folder("D"); //D盘
  //D盘下有文件-美女图片.png
  //D盘下有文件夹Mive-包含:私密网站.txt、截图.jpg
  f1 = new ImageFile("美女图片.png");
  Folder mive = new Folder("Mive"); //Move文件夹
  f2 = new TextFile("私密网站.txt");
  f3 = new ImageFile("截图.jpg");
  mive.add(f2);
  mive.add(f3);
  
  D.add(f1);
  D.add(mive);
  //开始查杀
  D.killVirvs();
 } 
}

4)案例效果

1.4、总结及建议

​ 一般涉及到数据结构方面的内容且符合树型结构的首先可以想到组合模式。

应用场景:

​ 当您需要实现树状结构时,请使用组合模式。比如:操作系统资源管理器、OA系统的组织结构、XML文件解析等;

JDK中组合模式的应用:

java.awt.Container#add(Component)

javax.faces.component.UIComponent#getChildren()