设计模式学习(六)——组合模式

组合模式定义

组合模式(Composite Pattern)通过组合多个对象形成树型结构,以表示“整体-部分”的结构层次。组合模型对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性。换句话说,在大多数情况下,我们可以忽略对象组合和个别对象之间的差别。

组合结构内的任意对象称为组件,组件可以是组合,也可以是叶子节点。

在使用组合模式时,通常要在透明性和安全性之间折衷。


组合模式结构图

图中:

  • Component表示抽象构件,它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现,在抽象构件中还定义了访问及管理子构件的方法,如增加子构件、删除子构件、获取子构件等;

  • Leaf表示叶子构件,在组合中表示叶子节点对象,它没有子节点,它实现抽象构件接口声明的基本行为;

  • Composite表示容器构件,它定义包含子节点(可以是叶子节点或容器节点)的构件的行为,并存储子节点(叶子节点或容器节点),它实现抽象构件接口中定义的操作叶子构件的行为;

  • Client表示客户类,它通过Component接口控制组合构件中的对象。


组合模式实例——杀毒软件

实例说明

使用组合模式设计一个杀毒软件(AntiVirus)的框架,该软件既可以对某个文件夹(Folder)杀毒,也可以对某个指定的文件(File)进行杀毒,文件种类包括文本文件TextFile、图片文件ImageFile、视频文件VideoFile。绘制类图并编程模拟实现。

实例类图

实例类图中与组合模式结构图对应的类主要有:

  • AbstractFile充当抽象构件类;

  • TextFile、ImageFile和VideoFile充当叶子构件类;

  • Folder充当容器构件类。

实例代码

AbstractFile.java:

//抽象文件类:抽象构件
abstract class AbstractFile
{
public abstract void add(AbstractFile element);
public abstract void remove(AbstractFile element);
public abstract void display();
}

TextFile.java:

//文本文件类:叶子构件
class TextFile extends AbstractFile
{
private String fileName;
public TextFile(String fileName)
{

this.fileName=fileName;
}
public void add(AbstractFile element)
{

System.out.println("对不起,不支持该方法!");
}
public void remove(AbstractFile element)
{

System.out.println("对不起,不支持该方法!");
}
public void display()
{

System.out.println("浏览文本文件:" + fileName);
}
}

ImageFile.java:

// 图片文件类:叶子构件
class ImageFile extends AbstractFile
{
private String fileName;
public ImageFile(String fileName)
{

this.fileName=fileName;
}
public void add(AbstractFile element)
{

System.out.println("对不起,不支持该方法!");
}
public void remove(AbstractFile element)
{

System.out.println("对不起,不支持该方法!");
}
public void display()
{

System.out.println("浏览图片文件:" + fileName);
}
}

VideoFile.java:

//视频文件类:叶子构件
class VideoFile extends AbstractFile
{
private String fileName;
public VideoFile(String fileName)
{

this.fileName=fileName;
}
public void add(AbstractFile element)
{

System.out.println("对不起,不支持该方法!");
}
public void remove(AbstractFile element)
{

System.out.println("对不起,不支持该方法!");
}
public void display()
{

System.out.println("浏览视频文件:" + fileName);
}
}

Folder.java:

import java.util.*;

//文件夹类:容器构件
class Folder extends AbstractFile
{

private ArrayList fileList=new ArrayList();
private String fileName;
public Folder(String fileName)
{

this.fileName=fileName;
}
public void add(AbstractFile element)
{

fileList.add(element);
}
public void remove(AbstractFile element)
{

fileList.remove(element);
}
public void display()
{

System.out.println("文件夹 - " + fileName + " - 包含如下资料:");
for(Object obj : fileList)
{
((AbstractFile)obj).display();
}
}
}

Client.java:

//客户端测试类
class Client
{
public static void main(String args[])
{
AbstractFile file1,file2,file3,file4,file5,folder1,folder2,folder3;
file1 = new ImageFile("房子.gif");
file2 = new ImageFile("美女.jpg");
file3 = new TextFile("设计模式.txt");
file4 = new TextFile("Java程序设计.doc");
file5 = new VideoFile("非诚勿扰.rmvb");
folder1 = new Folder("最新图片");
folder1.add(file1);
folder1.add(file2);
folder2 = new Folder("学习资料");
folder2.add(file3);
folder2.add(file4);
folder3 = new Folder("个人资料");
folder3.add(file5);
folder3.add(folder1);
folder3.add(folder2);
folder3.display();
}
}

运行结果

附加描述

本实例使用了透明组合模式,在抽象构件类中定义了所有方法,包括用于管理子构件的方法,如add()方法和remove()方法,因此在TextFile等叶子构件类中实现这些方法时必须进行相应的异常处理或错误提示。在容器构件Folder的display()方法中递归调用其成员对象的display()方法,从而实现对整个树型结构的遍历。


后话

组合模式的思想就是利用树型结构来管理构件,和我们熟悉的文件夹下面有文件夹或文件的存储方式一致,理解起来也不困难。