python 设计模式之组合模式Composite Pattern

 #引入一

文件夹对我们来说很熟悉,文件夹里面可以包含文件夹,也可以包含文件。

那么文件夹是个容器,文件夹里面的文件夹也是个容器,文件夹里面的文件是对象。

 这是一个树形结构

咱们生活工作中常用的一种结构

文件是一个简单对象,我直接打开就可以使用。文件夹是复杂对象,因为里面还有子文件夹 或者是文件。

 我在用这个文件夹的时候,我用相同的方式对待文件夹和文件。

其实这时候我们就是在使用设计模式中的组合模式了了

#引入二

这是从人家的博客上截的图

公司的组织架构也是常用的树形结构,也适合使用组合模式

#组合模式定义

 组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。

 #使用场景

1、想表示对象的部分-整体层次结构(树形结构)。

2、希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中

3‘如果你想要创建层次结构,并可以在其中以相同的方式对待所有元素,那么组合模式就是最理想的选择

#涉及角色

百度百科粘过来的

1.Component 是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
2.Leaf 在组合中表示叶子结点对象,叶子结点没有子结点。

3.Composite 定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等

#组合模式的优点

 组合模式的主要优点如下:

      (1) 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。

      (2) 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。

      (3) 在组合模式中增加新的容器构件和叶子构件都很方便,无须对现有类库进行任何修改,符合“开闭原则”。

      (4) 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

#组合模式的缺点

 组合模式的主要缺点如下:

      在增加新构件时很难对容器中的构件类型进行限制。有时候我们希望一个容器中只能有某些特定类型的对象,例如在某个文件夹中只能包含文本文件,使用组合模式时,不能依赖类型系统来施加这些约束,因为它们都来自于相同的抽象层,在这种情况下,必须通过在运行时进行类型检查来实现,这个实现过程较为复杂。

#组合模式有两种

(1) 透明组合模式

      透明组合模式中,抽象构件Component中声明了所有用于管理成员对象的方法,包括add()、remove()以及getChild()等方法,这样做的好处是确保所有的构件类都有相同的接口。在客户端看来,叶子对象与容器对象所提供的方法是一致的,客户端可以相同地对待所有的对象。透明组合模式也是组合模式的标准形式。

      透明组合模式的缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的。叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供add()、remove()以及getChild()等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没有提供相应的错误处理代码)。

 (2) 安全组合模式

  安全组合模式中,在抽象构件Component中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法。这种做法是安全的,因为根本不向叶子对象提供这些管理成员对象的方法,对于叶子对象,客户端不可能调用到这些方法。

安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。在实际应用中,安全组合模式的使用频率也非常高,在Java AWT中使用的组合模式就是安全组合模式。

  #举个栗子 (python实现组合模式)

#抽象一个组织类
class Component:
    def __init__(self,name):
        self.name=name

    def add(self,comp):
        pass
    def remove(slef,comp):
        pass
    def display(self,depth):
        pass

#叶子节点
class Leaf(Component):
    def add(self):
        print('不能添加子节点')
    def remove(self):
        print('不能删除子节点')
    def display(self,depth):
        strtemp=''
        for i in range(depth):
            strtemp +='---'
        print(strtemp+self.name)

#枝节点
class Composite(Component):
    def __init__(self,name):
        self.name=name
        self.children=[]
    def add(self,comp):
        self.children.append(comp)
    def remove(self,comp):
        self.children.remove(comp)
    def display(self,depth):
        strtemp=''
        for i in range(depth):
            strtemp += '---'
        print(strtemp+self.name)
        for comp in self.children:
            comp.display(depth+2)

if __name__=='__main__':
    root=Composite('根')
    
    root.add(Leaf('叶1a'))
    root.add(Leaf('叶1b'))
    root.add(Leaf('花1a'))
    root.add(Leaf('花1b'))
    comp1a=Composite('枝1a')
    comp1b=Composite('枝1b')
    root.add(comp1a)
    root.add(comp1b)

    comp1a.add(Leaf('叶2a'))
    comp1a.add(Leaf('叶2b'))
    comp1a.add(Leaf('花2a'))
    comp1a.add(Leaf('花2b'))
    comp2a=Composite('枝2a')
    comp1a.add(comp2a)

    comp1b.add(Leaf('叶2a'))
    comp1b.add(Leaf('花2a'))

    comp2a.add(Leaf('叶3a'))
    comp2a.add(Leaf('花3a'))
    comp3a=Composite('枝3a')
    comp2a.add(comp3a)

    comp3a.add(Leaf('叶4a'))
    comp3a.add(Leaf('花4a')) 
    
    root.display(1)
    

 

参考

https://www.cnblogs.com/fxycm/p/4887680.html

https://baike.baidu.com/item/%E7%BB%84%E5%90%88%E6%A8%A1%E5%BC%8F/1441281

https://www.cnblogs.com/lfxiao/p/6816026.html

https://www.runoob.com/design-pattern/composite-pattern.html

https://www.jianshu.com/p/68ada9b3cff9

还有参考其他链接,忘记贴地址了

原文地址:https://www.cnblogs.com/baxianhua/p/11350253.html