github地址:https://github.com/cheesezh/python_design_patterns

组合模式

组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和对组合对象的使用具有一致性[DP]。

from abc import ABCMeta, abstractmethod

class Component():
"""
Component为组合中的对象声明接口,在适当情况下,实现所有类共有接口的默认行为。
声明一个接口用于访问和管理Component的子部件。
"""
__metaclass__ = ABCMeta def __init__(self, name):
self.name = name @abstractmethod
def add(self, c):
"""
通常用add来增加树枝或树叶
"""
pass @abstractmethod
def remove(self, c):
"""
通常用remove来删除树枝或树叶
"""
pass @abstractmethod
def display(self, depth):
pass class Leaf(Component):
"""
叶子节点
"""
def add(self, c):
print("叶子节点无法添加子节点") def remove(self, c):
print("叶子节点无法删除子节点") def display(self, depth):
print("-"*depth, self.name) class Composite(Component):
"""
子部件节点
"""
def __init__(self, name):
super().__init__(name)
self.children = [] def add(self, c):
self.children.append(c) def remove(self, c):
self.children.remove(c) def display(self, depth):
print("-"*depth, self.name)
for c in self.children:
c.display(depth+2) def main():
root = Composite("root")
root.add(Leaf("Leaf A"))
root.add(Leaf("Leaf B")) comp = Composite("Composite X")
comp.add(Leaf("Leaf XA"))
comp.add(Leaf("Leaf XB")) root.add(comp) comp2 = Composite("Composite XY")
comp2.add(Leaf("Leaf XYA"))
comp2.add(Leaf("Leaf XYB")) comp.add(comp2) root.add(Leaf("Leaf C")) leaf_d = Leaf("Leaf D")
root.add(leaf_d)
root.remove(leaf_d) root.display(1) main()
- root
--- Leaf A
--- Leaf B
--- Composite X
----- Leaf XA
----- Leaf XB
----- Composite XY
------- Leaf XYA
------- Leaf XYB
--- Leaf C

透明方式与安全方式

Leaf类中也有Add和Reomve,但是树叶不可以再长分枝。这种方式叫做透明方式,也就是说再Component中声明所有用来管理子对象的方法,其中包括add,remove等。这样Component抽象类的所有子类都具备了add和remove。这样的好处在于叶子节点和分枝节点对于外界没有区别,它们具备完全一致的行为接口。但是问题也比较明显,因为Leaf类本身不具备add和remove等功能,所以实现它是没有意义的。

另一种是安全方式,也就是在Component接口中不去声明add和remove方法,那么子类Leaf也就不需要去实现它,而是在Composite声明所有用来管理子类对象的方法,这样做就不会出现刚才提到的问题,不过由于不透明,所以树叶和树枝类将有不同的接口,客户端调用需要做相应的判断,带来了不便。

何时使用组合模式

当需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式了。

题目

使用组合模式,模拟公司管理系统。

from abc import ABCMeta, abstractmethod

class Company():
"""
抽象公司类
"""
__metaclass__ = ABCMeta def __init__(self, name):
self.name = name @abstractmethod
def add(self, c):
"""
通常用add来增加树枝或树叶
"""
pass @abstractmethod
def remove(self, c):
"""
通常用remove来删除树枝或树叶
"""
pass @abstractmethod
def display(self, depth):
pass @abstractmethod
def line_of_duty(self):
pass class ConcreteCompany(Company):
"""
具体公司类
"""
def __init__(self, name):
super().__init__(name)
self.children = [] def add(self, c):
self.children.append(c) def remove(self, c):
self.children.remove(c) def display(self, depth):
print("-"*depth, self.name)
for c in self.children:
c.display(depth+2) def line_of_duty(self):
for c in self.children:
c.line_of_duty() class HRDepartment(Company):
"""
人力资源部
"""
def add(self, c):
pass def remove(self, c):
pass def display(self, depth):
print("-"*depth, self.name) def line_of_duty(self):
print("{}负责员工招聘。".format(self.name)) class FinanceDepartment(Company):
"""
财务部
"""
def add(self, c):
pass def remove(self, c):
pass def display(self, depth):
print("-"*depth, self.name) def line_of_duty(self):
print("{}负责财务收支。".format(self.name)) def main():
root = ConcreteCompany("北京总公司")
root.add(HRDepartment("总公司人力资源部"))
root.add(FinanceDepartment("总公司财务部")) comp = ConcreteCompany("上海华东分公司")
comp.add(HRDepartment("华东分公司人力资源部"))
comp.add(FinanceDepartment("华东分公司财务部"))
root.add(comp) comp1 = ConcreteCompany("南京办事处")
comp1.add(HRDepartment("南京办事处人力资源部"))
comp1.add(FinanceDepartment("南京办事处财务部"))
comp.add(comp1) comp2 = ConcreteCompany("杭州办事处")
comp2.add(HRDepartment("杭州办事处人力资源部"))
comp2.add(FinanceDepartment("杭州办事处财务部"))
comp.add(comp2) print("组织架构图")
root.display(1) print("履行职责")
root.line_of_duty() main()
组织架构图
- 北京总公司
--- 总公司人力资源部
--- 总公司财务部
--- 上海华东分公司
----- 华东分公司人力资源部
----- 华东分公司财务部
----- 南京办事处
------- 南京办事处人力资源部
------- 南京办事处财务部
----- 杭州办事处
------- 杭州办事处人力资源部
------- 杭州办事处财务部
履行职责
总公司人力资源部负责员工招聘。
总公司财务部负责财务收支。
华东分公司人力资源部负责员工招聘。
华东分公司财务部负责财务收支。
南京办事处人力资源部负责员工招聘。
南京办事处财务部负责财务收支。
杭州办事处人力资源部负责员工招聘。
杭州办事处财务部负责财务收支。

点评

组合模式定义了包含人力资源部和财务部这些基本对象和分公司,办事处等组合对象的类层次结构。基本对象可以被组合成共复杂的组合对象,而这个组合对象又可以被组合,这样不断地递归下去,客户端代码中,任何用到基本对象的地方都可以使用组合对象了。用户不用关心到底是处理一个叶子节点还是处理一个组合组件,也用不着为定义组合而写一些选择判断语句。

简单的说,组合模式让客户可以一致地使用组合结构和单个对象。

[Python设计模式] 第19章 分公司=部门?——组合模式的更多相关文章

  1. [Python设计模式] 第1章 计算器——简单工厂模式

    github地址:https://github.com/cheesezh/python_design_patterns 写在前面的话 """ 读书的时候上过<设计模 ...

  2. [Python设计模式] 第13章 造小人——建造者模式

    github地址:https://github.com/cheesezh/python_design_patterns 题目1 用程序模拟一个画小人的过程,要求小人要有头,身子,左手,右手,左脚,右脚 ...

  3. javascript设计模式(张容铭) 第14章 超值午餐-组合模式 学习笔记

    JS 组合模式更常用于创建表单上,比如注册页面可能有不同的表单提交模块.对于这些需求我们只需要有基本的个体,然后通过一定的组合即可实现,比如下面这个页面样式(如图14-2所示),我们来用组合模式实现. ...

  4. 设计模式(九):Composite组合模式 -- 结构型模式

    1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 我们可以使用简单的对象组合成复杂的对象,而这个复杂对 ...

  5. 【设计模式】学习笔记13:组合模式(Composite)

    本文出自   http://blog.csdn.net/shuangde800 认识组合模式 上一篇中,我们可以用迭代器来实现遍历一个集合(数组,ArrayList, Vector, HashTabl ...

  6. Java设计模式偷跑系列(十二)组合模式建模和实现

    转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39828653 组合模式(Composite):组合模式有时又叫部分-总体模式.将对象组合成 ...

  7. [Python设计模式] 第21章 计划生育——单例模式

    github地址:https://github.com/cheesezh/python_design_patterns 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式 ...

  8. [Python设计模式] 第26章 千人千面,内在共享——享元模式

    github地址:https://github.com/cheesezh/python_design_patterns 背景 有6个客户想做产品展示网站,其中3个想做成天猫商城那样的"电商风 ...

  9. [Python设计模式] 第22章 手机型号&软件版本——桥接模式

    github地址:https://github.com/cheesezh/python_design_patterns 紧耦合程序演化 题目1 编程模拟以下情景,有一个N品牌手机,在上边玩一个小游戏. ...

随机推荐

  1. 069 在SparkStreaming的窗口分析

    一:说明 1.图例说明 ---------------------------------------------------------------------------------------- ...

  2. quratz数据存储

    Quartz 中的 trigger 和 job 需要存储下来才能被使用. 1.两种存储方式 RAMJobStore, JobStoreSupport, 其中 RAMJobStore 是将 trigge ...

  3. Spring(二)IOC底层实现原理

    IOC原理 将对象创建交给Spring去管理. 实现IOC的两种方式 IOC配置文件的方式 IOC注解的方式 IOC底层实现原理 底层实现使用的技术 1.1 xml配置文件 1.2 dom4j解析xm ...

  4. Stm32串口通信(USART)

    Stm32串口通信(UART) 串口通信的分类 串口通信三种传递方式 串口通信的通信方式 串行通信的方式: 异步通信:它用一个起始位表示字符的开始,用停止位表示字符的结束.其每帧的格式如下: 在一帧格 ...

  5. Ef 自动迁移,日志

    Ef 迁移 在vs打开程序控制台 2,选择程序集 ,如果是初次,输入 Enable-Migrations,启动迁徙 3  添加迁移,完成修改 4,之后会自动生成迁移配置文件. 然后再上下文类中加入 两 ...

  6. MySQL数据库基本用法-聚合-分组

    聚合 为了快速得到统计数据,提供了5个聚合函数 count(*)表示计算总行数,括号中写星与列名,结果是相同的 查询学生总数 select count(*) from students; max(列) ...

  7. Unity IOC容器的构造函数使用笔记(不能错过的Unity示例)

    示例一,正常使用: 相关定义: public interface ICar { int Run(); } public class BMW : ICar { ; public int Run() { ...

  8. node安装及配置之windows版

    一.下载地址 https://nodejs.org/zh-cn/download/ https://nodejs.org/zh-cn/download/releases/ 二.安装步骤 1.双击“no ...

  9. 深入理解arguments.callee

    在函数内部,有两个特殊的对象:arguments 和 this.其中, arguments 的主要用途是保存函数参数, 但这个对象还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 a ...

  10. 网上的很多Android项目源码有用吗?Android开发注意的地方。

    在Android项目开发中,我们可以在网上看到很多项目源码,大部分也不是很精致, 比如 06.Android阿福多媒体播放器开发教程+源码 还有什么浏览器源码. 那么这些有用吗?  价值在哪里? 精致 ...