文章目录
前言
GOF设计模式分三大类:
- 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。
- 结构型模式:关注类和对象之间的组合,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。
- 行为型模式:关注对象之间的交互,包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。
一、组合模式
组合模式(Composite Pattern)
-
定义:组合多个对象形成树形结构以表示具有"部分---整体"关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,又可以称为"部分---整体"(Part-Whole)模式。
-
解决问题:如何使用面向对象的方式来处理软件系统中的树形结构?
-
使用场景:
- 在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致性地对待它们。
- 在一个使用面向对象语言开发的系统中需要处理一个树形结构。
- 在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,将来需要增加一些新的类型。
- 在XML解析、组织结构树处理、文件系统设计等领域,组合模式都得到了广泛应用。
-
组成:
- 抽象构件(Component):它是所有容器类和叶子类的公共父类,为叶子构件和容器构件对象声明接口。一般将抽象构件类设计为接口或抽象类,将所有子类共有方法的声明和实现放在抽象构件类中。对于客户端而言,将针对抽象构件编程,而无须关心其具体子类是容器构件还是叶子构件。
- 叶子构件(Leaf):代表组合结构中的叶节点对象,叶节点对象不再包含子节点。
- 容器构件(Composite):它在组合模式结构中表示容器节点对象。容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点。用列表实现容器构件。
-
补充说明
- 组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器。客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。
- 容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。
-
优点:
- 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次。客户端无须关心节点的层次结构,可以对所选节点进行统一处理,提高系统的灵活性。
- 将容器对象和叶子对象进行递归组合,实现简单,灵活性好,使用频率较高。
- 在组合模式中增加新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改,符合开闭原则。
- 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案。
-
缺点:
- 在增加新构件时很难对容器中的构件类型进行限制。
二、组合模式实现方式
实现方式一:透明组合模式
- 根据抽象构件类的定义形式,可将组合模式分为透明组合模式和安全组合模式两种形式。
- 抽象构件Component中声明了所有用于管理成员对象的方法,包括add()、remove()以及getChild()等方法
- 透明组合模式结构图
实现方式二:安全组合模式
- 抽象构件Component中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法。
- 安全组合模式结构图
三、组合模式示例
使用透明组合模式来进行杀毒软件的框架设计
- AbstractFile充当抽象构件类,Folder充当容器构件类,ImageFile、TextFile和VideoFile充当叶子构件类
python
"""抽象构件"""
class AbstracFile:
def add(self, file):
raise NotImplementedError
def remove(self, file):
raise NotImplementedError
def kill_virus(self):
raise NotImplementedError
"""容器构件"""
class Folder(AbstracFile):
def __init__(self, name):
self.name = name
self.file_list: list[AbstracFile] = []
def add(self, file):
self.file_list.append(file)
def remove(self, file):
if file in self.file_list:
self.file_list.remove(file)
def kill_virus(self):
# 模拟杀毒
print(f"------对文件夹 {self.name} 进行杀毒")
# 循环调用成员构件的业务方法
for i in self.file_list:
i.kill_virus()
"""叶子构件"""
class ImageFile(AbstracFile):
def __init__(self, name):
self.name = name
def kill_virus(self):
# 模拟杀毒
print(f"------对图像文件 {self.name} 进行杀毒")
class TextFile(AbstracFile):
def __init__(self, name):
self.name = name
def kill_virus(self):
# 模拟杀毒
print(f"------对文本文件 {self.name} 进行杀毒")
class VideoFile(AbstracFile):
def __init__(self, name):
self.name = name
def kill_virus(self):
# 模拟杀毒
print(f"------对视频文件 {self.name} 进行杀毒")
客户端代码
python
# 针对抽象构件编程
folder1 = Folder("张三的资料")
folder2 = Folder("图像文件")
folder3 = Folder("文本文件")
folder4 = Folder("视频文件")
file1 = ImageFile("《洛神赋图》.gif")
file2 = ImageFile("《清明上河图》.jpg")
file3 = TextFile("《分析与设计》.txt")
file4 = TextFile("《设计模式》.doc")
file5 = VideoFile("《西游记》.rmvb")
folder2.add(file1)
folder2.add(file2)
folder3.add(file3)
folder3.add(file4)
folder4.add(file5)
folder1.add(folder2)
folder1.add(folder3)
folder1.add(folder4)
folder1.kill_virus()
# 也可以创建图形化界面让用户选择所需操作的根节点,无须修改源代码,符合开闭原则。
# folder2.kill_virus()
输出结果
sh
------对文件夹 张三的资料 进行杀毒
------对文件夹 图像文件 进行杀毒
------对图像文件 《洛神赋图》.gif 进行杀毒
------对图像文件 《清明上河图》.jpg 进行杀毒
------对文件夹 文本文件 进行杀毒
------对文本文件 《分析与设计》.txt 进行杀毒
------对文本文件 《设计模式》.doc 进行杀毒
------对文件夹 视频文件 进行杀毒
------对视频文件 《西游记》.rmvb 进行杀毒
四、组合模式在Django中的应用
Django 的 admin 界面允许用户以树形结构来组织模型。例如,一个 Group
可以包含多个 User
,而 User
又可以属于多个 Group
。在 admin 界面中,这种关系可以用组合模式来实现,其中 Group
可以看作是组合对象,而 User
可以看作是叶节点。
您正在阅读的是《设计模式Python版》专栏!关注不迷路~