复合方法 - Python设计模式
复合方法是一种结构设计模式,它描述了一组对象,这些对象的处理方式与相同类型对象的单个实例相同。复合方法的目的是将对象组合成树型结构以表示整体部分层次结构。
使用复合方法的主要优点之一是,首先,它允许您将对象组合成树结构,然后将这些结构作为单独的对象或实体使用。
您可以对所有复合对象执行的操作通常具有最小公分母关系。
复合模式有四个参与者:
- 组件:组件有助于实现所有类通用接口的默认行为。它声明组合中对象的接口,并用于访问和管理其子组件。
- 叶:它定义组合中原始对象的行为。它表示合成中的叶子对象。
- Composite:存储子组件,并在组件接口中实现子相关操作。
- 客户端:用于通过组件接口对组合中的对象进行操作。
不使用复合方法的问题
想象一下,我们正在研究一个由总经理、经理和开发人员组成的组织结构。一个总经理可能有很多经理在他手下工作,一个经理可能有很多开发人员在他手下工作。
假设,您必须确定所有员工的总工资。那么,您将如何确定呢?
一个普通的开发者肯定会尝试直接的方法,遍历每个员工并计算总工资。看起来很容易?在实施方面并非如此。因为我们必须知道所有员工总经理、经理和开发人员的类别。
在基于树的结构中通过直接方法进行计算似乎是一项不可能完成的任务。
使用复合方法的解决方案
上述问题的最佳解决方案之一是通过使用声明计算总工资的方法的通用接口来使用复合方法。
每当我们有“包含组件的复合材料,每个组件都可以是复合材料”时,我们通常会使用复合方法。
"""Here we attempt to make an organizational hierarchy with sub-organization,
which may have subsequent sub-organizations, such as:
GeneralManager [Composite]
Manager1 [Composite]
Developer11 [Leaf]
Developer12 [Leaf]
Manager2 [Composite]
Developer21 [Leaf]
Developer22 [Leaf]"""
class LeafElement:
'''Class representing objects at the bottom or Leaf of the hierarchy tree.'''
def __init__(self, *args):
''''Takes the first positional argument and assigns to member variable "position".'''
self.position = args[0]
def showDetails(self):
'''Prints the position of the child element.'''
print("\t", end ="")
print(self.position)
class CompositeElement:
'''Class representing objects at any level of the hierarchy
tree except for the bottom or leaf level. Maintains the child
objects by adding and removing them from the tree structure.'''
def __init__(self, *args):
'''Takes the first positional argument and assigns to member
variable "position". Initializes a list of children elements.'''
self.position = args[0]
self.children = []
def add(self, child):
'''Adds the supplied child element to the list of children
elements "children".'''
self.children.append(child)
def remove(self, child):
'''Removes the supplied child element from the list of
children elements "children".'''
self.children.remove(child)
def showDetails(self):
'''Prints the details of the component element first. Then,
iterates over each of its children, prints their details by
calling their showDetails() method.'''
print(self.position)
for child in self.children:
print("\t", end ="")
child.showDetails()
"""main method"""
if __name__ == "__main__":
topLevelMenu = CompositeElement("GeneralManager")
subMenuItem1 = CompositeElement("Manager1")
subMenuItem2 = CompositeElement("Manager2")
subMenuItem11 = LeafElement("Developer11")
subMenuItem12 = LeafElement("Developer12")
subMenuItem21 = LeafElement("Developer21")
subMenuItem22 = LeafElement("Developer22")
subMenuItem1.add(subMenuItem11)
subMenuItem1.add(subMenuItem12)
subMenuItem2.add(subMenuItem22)
subMenuItem2.add(subMenuItem22)
topLevelMenu.add(subMenuItem1)
topLevelMenu.add(subMenuItem2)
topLevelMenu.showDetails()
输出:
GeneralManager
Manager1
Developer11
Developer12
Manager2
Developer22
Developer22
复合方法类图
以下是Composite Method的一般类图:
好处
- 开闭原则:由于允许在应用程序中引入新的元素、类和接口而不破坏客户端现有的代码,所以肯定遵循开闭原则
- 更少的内存消耗:与普通方法相比,我们必须创建更少的对象,这肯定会减少内存使用量,也可以让我们远离与内存相关的错误
- 改进的执行时间:在Python中创建对象并不需要太多时间,但我们仍然可以通过共享对象来减少程序的执行时间。
- 灵活性:它通过可管理的类或接口提供结构的灵活性,因为它定义了包含原始和复杂对象的类层次结构。
缺点
- 对组件的限制:复合方法使得限制复合组件的类型变得更加困难。当您不想表示对象的完整或部分层次结构时,不建议使用它。
- 通用树结构:一旦定义了树的结构,复合方法将生成整体通用树。
- 语言的类型系统:由于不允许使用编程语言的类型系统,我们的程序必须依赖运行时检查来应用约束。
适用性
- 嵌套树结构的要求:当您需要生成树的嵌套结构时,最好使用复合方法,其中再次包括叶子对象和其他对象容器。
- 图形编辑器:我们可以将形状定义为简单的类型——直线或复杂的类型——矩形。由于所有的形状都有很多共同的操作,比如将形状渲染到屏幕上,所以可以使用复合图案使程序能够统一处理所有的形状。
进一步阅读: Java中的复合方法