软件设计模式 | 结构型之组合模式(安全方式与透明方式)


组合模式

在这里插入图片描述
   图中的文件结构可以称之为树形结构,在数据结构中我们可以通过调用某个方法来遍历整棵树,当我们找到某个叶子节点后,就可以对叶子节点进行相关的操作。我们可以将这颗树理解成一个大的容器,容器里面包含很多的成员对象,这些成员对象即可是容器对象也可以是叶子对象。但是由于容器对象和叶子对象在功能上面的区别,使得我们在使用的过程中必须要区分容器对象和叶子对象,但是这样就会给客户带来不必要的麻烦,作为客户而已,它始终希望能够一致的对待容器对象和叶子对象。
   组合模式的设计动机:组合模式定义了如何将容器对象和叶子对象进行递归组合,使得客户在使用的过程中无须进行区分,可以对他们进行一致的处理。


一、模式定义

  组合模式组合多个对象形成树形结构以表示“整体-部分”的结构层次。

  组合模式对单个对象(叶子对象)和组合对象(组合对象)具有一致性,它将对象组织到树结构中,可以用来描述整体与部分的关系。同时它也模糊了简单元素(叶子对象)和复杂元素(容器对象)的概念,使得客户能够像处理简单元素一样来处理复杂元素,从而使客户程序能够与复杂元素的内部结构解耦。
  上面的图种的文件系统,文件系统由文件和目录组成,目录下面也可以包含文件或者目录,计算机的文件系统是用递归结构来进行组织的,对于这样的数据结构是非常适用使用组合模式的。

  在使用组合模式中需要注意一点也是组合模式最关键的地方:叶子对象和组合对象实现相同的接口。这就是组合模式能够将叶子节点和对象节点进行一致处理的原因。


二、模式结构

在这里插入图片描述
组合模式主要包含如下几个角色:

1. Component : 组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
2. Leaf: 叶子对象。叶子结点没有子结点。
3. Composite: 容器对象,定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。
  从模式结构中我们看出了叶子节点和容器对象都实现Component接口,这也是能够将叶子对象和容器对象一致对待的关键所在。


注意:
 1. 这里的 Component 即可以是接口也可以是抽象类,都是通过子类去实现抽象的方法,在这里不做区分。
 2. Component 是否有 add() 方法和 remove() 方法是有区分的,如果没有以上两种方法,那么叫做 安全方式 。如果有以上两种方法,叫 透明方式

下面两道例题可以用来做区分。


三、 模式实现

3.1 水果盘问题 (安全方式)

  在水果盘(Plate)中有一些水果,如 苹果(Apple) 、香蕉(Banana) 、 梨(Pear) ,当然 大水果盘中还可以有小水果盘 ,现需要对盘中的水果进行遍历( 吃 ),当然如果对一 个 水 果 盘执行 “吃 ”方法,实际上就是吃其中的水果。使用组合模式模拟该场景。
类图如下:
在这里插入图片描述

Component:组合对象的声明接口

public abstract class MyElement {
    public abstract void eat();
}

Leaf:叶子节点,包括苹果、香蕉、梨

public class Apple extends MyElement {
     public void eat(){
       System.out.println("eat apple !");
     }
}
public class Banana extends MyElement {
    public void eat(){
        System.out.println("eat Banana !");
    }
}
public class Pear extends MyElement {
    public void eat(){
        System.out.println("eat Pear !");
    }
}

Composite:容器对象

public class Plate extends MyElement {
     private ArrayList<MyElement> list = new ArrayList();
     public void add(MyElement element) {
         list.add(element);
     }
     public void delete(MyElement element) {
        list.remove(element);
     }
     public void eat() {
          for(MyElement element: list) {
              element.eat();
          }
          System.out.println("--------------------");//用于分隔
     }
}

演示:客户端代码

public class Client{
    public static void main(String[] args) {
       MyElement obj1, obj2, obj3, obj4, obj5;
       Plate plate1, plate2, plate3;

       obj1 = new Apple();
       obj2 = new Pear();
       plate1 = new Plate();
       plate1.add(obj1);//盘子1放苹果和梨
       plate1.add(obj2);

       obj3 = new Banana();
       obj4 = new  Banana();
       plate2 = new Plate();
       plate2.add(obj3);//盘子2放两个香蕉
       plate2.add(obj4);

       obj5 = new Apple();
       plate3 = new Plate();

       plate3.add(plate1);
       plate3.add(plate2);
       plate3.add(obj5);//盘子3放盘子1、盘子2和苹果

       plate3.eat();
    }
}

结果展示:
在这里插入图片描述


3.2 杀毒软件 (透明方式)

  使用组合模式设计一个杀毒软件(AntiVirus)的框架,该软件既可以对某个文件夹(Folder)杀毒,也可以对某个指定的文件(File)进行杀毒,文件种类包括文本文件TextFile、图片文件ImageFile、视频文件VideoFile。绘制类图并编程模拟实现。
类图如下:
在这里插入图片描述
Component:组合对象的声明接口

public interface AbstractFile {
    void add(AbstractFile file);
    void remove(AbstractFile file);
    void killVirus();
}

Leaf:叶子节点,包括图像文件、文本文件以及视频文件

class ImageFile implements AbstractFile {		//图像文件类:叶子构件
  private String name;  
  public ImageFile(String name) {  
      this.name = name;  
  }  
  public void add(AbstractFile file) {  
     System.out.println("对不起,不支持该方法!");  
  }  
  public void remove(AbstractFile file) {  
      System.out.println("对不起,不支持该方法!");  
  }  

  public void killVirus() {  
      //模拟杀毒  
      System.out.println("----对图像文件'" + name + "'进行杀毒");  
  }  
}
class TextFile implements AbstractFile {		//文本文件类:叶子构件
  private String name;
  public TextFile(String name) {
      this.name = name;  
  }  
  public void add(AbstractFile file) {  
     System.out.println("对不起,不支持该方法!");  
  }  
  public void remove(AbstractFile file) {  
      System.out.println("对不起,不支持该方法!");  
  }  

  public void killVirus() {  
      //模拟杀毒  
      System.out.println("----对文本文件'" + name + "'进行杀毒");
  }  
}
class VideoFile implements AbstractFile {		//视频文件类:叶子构件
  private String name;
  public VideoFile(String name) {
      this.name = name;  
  }  
  public void add(AbstractFile file) {  
     System.out.println("对不起,不支持该方法!");  
  }  
  public void remove(AbstractFile file) {  
      System.out.println("对不起,不支持该方法!");  
  }  

  public void killVirus() {  
      //模拟杀毒  
      System.out.println("----对视频文件'" + name + "'进行杀毒");
  }  
}

Composite:容器对象

class Folder implements AbstractFile {		//文件夹类:容器构件
  //定义集合fileList,用于存储AbstractFile类型的成员  
  private ArrayList<AbstractFile> list=new ArrayList();
  private String name;  
  public Folder(String name) {  
      this.name = name;  
  }  
  public void add(AbstractFile file) {
      list.add(file);
  }  
  public void remove(AbstractFile file) {
      list.remove(file);
  }  

  public void killVirus() {  
      System.out.println("****对文件夹'" + name + "'进行杀毒");  //模拟杀毒  
      //递归调用成员构件的killVirus()方法  
      for(AbstractFile file : list) {
          file.killVirus();
      }
  }  
}

演示:客户端代码

class Client {		//客户端类
	public static void main(String args[]) {
        //针对抽象构件编程
		AbstractFile file1, file2, file3, file4, file5;
		AbstractFile folder1,folder2, folder3;
		folder1 = new Folder("文本文件");
		folder2 = new Folder("图像文件");
		folder3 = new Folder("视频文件");

		file1 = new TextFile("记事本.txt");
		file2 = new ImageFile("转圈圈.gif");
		file3 = new ImageFile("跑步.png");
		file4 = new VideoFile("电影1.rmvb");
		file5 = new VideoFile("电影2.rmvb");

		folder1.add(file1);
		folder2.add(file2);
		folder2.add(file3);
		folder3.add(file4);
		folder3.add(file5);
		
		folder1.add(folder2);
		folder1.add(folder3);
		
		folder1.killVirus();
	}
}

结果展示:
在这里插入图片描述


四、 模式优缺点

优点:

  1. 可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构件也更容易。
  2. 客户端调用简单,客户端可以一致的使用组合结构或其中单个对象。
  3. 定义了包含叶子对象和容器对象的类层次结构,叶子对象可以被组合成更复杂的容器对象,而这个容器对象又可以被组合,这样不断递归下去,可以形成复杂的树形结构。
  4. 更容易在组合体内加入对象构件,客户端不必因为加入了新的对象构件而更改原有代码。

缺点:
  使设计变得更加抽象,对象的业务规则如果很复杂,则实现组合模式具有很大挑战性,而且不是所有的方法都与叶子对象子类都有关联。


五、 模式适用场景

1、需要表示一个对象整体或部分层次,在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,可以一致地对待它们。
2、让客户能够忽略不同对象层次的变化,客户端可以针对抽象构件编程,无须关心对象层次结构的细节。


六、 模式总结

  1. 组合模式用于将多个对象组合成树形结构以表示“整体-部分”的结构层次。组合模式对单个对象(叶子对象)和组合对象(容器对象)的使用具有一致性。

  2. 组合对象的关键在于它定义了一个抽象构建类,它既可表示叶子对象,也可表示容器对象,客户仅仅需要针对这个抽象构建进行编程,无须知道他是叶子对象还是容器对象,都是一致对待。

  3. 组合模式虽然能够非常好地处理层次结构,也使得客户端程序变得简单,但是它也使得设计变得更加抽象,而且也很难对容器中的构件类型进行限制,这会导致在增加新的构件时会产生一些问题。


参考博客:https://www.cnblogs.com/chenssy/p/3299719.html

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xiu Yan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值