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

组合模式

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

  1. from abc import ABCMeta, abstractmethod
  2. class Component():
  3. """
  4. Component为组合中的对象声明接口,在适当情况下,实现所有类共有接口的默认行为。
  5. 声明一个接口用于访问和管理Component的子部件。
  6. """
  7. __metaclass__ = ABCMeta
  8. def __init__(self, name):
  9. self.name = name
  10. @abstractmethod
  11. def add(self, c):
  12. """
  13. 通常用add来增加树枝或树叶
  14. """
  15. pass
  16. @abstractmethod
  17. def remove(self, c):
  18. """
  19. 通常用remove来删除树枝或树叶
  20. """
  21. pass
  22. @abstractmethod
  23. def display(self, depth):
  24. pass
  25. class Leaf(Component):
  26. """
  27. 叶子节点
  28. """
  29. def add(self, c):
  30. print("叶子节点无法添加子节点")
  31. def remove(self, c):
  32. print("叶子节点无法删除子节点")
  33. def display(self, depth):
  34. print("-"*depth, self.name)
  35. class Composite(Component):
  36. """
  37. 子部件节点
  38. """
  39. def __init__(self, name):
  40. super().__init__(name)
  41. self.children = []
  42. def add(self, c):
  43. self.children.append(c)
  44. def remove(self, c):
  45. self.children.remove(c)
  46. def display(self, depth):
  47. print("-"*depth, self.name)
  48. for c in self.children:
  49. c.display(depth+2)
  50. def main():
  51. root = Composite("root")
  52. root.add(Leaf("Leaf A"))
  53. root.add(Leaf("Leaf B"))
  54. comp = Composite("Composite X")
  55. comp.add(Leaf("Leaf XA"))
  56. comp.add(Leaf("Leaf XB"))
  57. root.add(comp)
  58. comp2 = Composite("Composite XY")
  59. comp2.add(Leaf("Leaf XYA"))
  60. comp2.add(Leaf("Leaf XYB"))
  61. comp.add(comp2)
  62. root.add(Leaf("Leaf C"))
  63. leaf_d = Leaf("Leaf D")
  64. root.add(leaf_d)
  65. root.remove(leaf_d)
  66. root.display(1)
  67. main()
  1. - root
  2. --- Leaf A
  3. --- Leaf B
  4. --- Composite X
  5. ----- Leaf XA
  6. ----- Leaf XB
  7. ----- Composite XY
  8. ------- Leaf XYA
  9. ------- Leaf XYB
  10. --- Leaf C

透明方式与安全方式

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

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

何时使用组合模式

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

题目

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

  1. from abc import ABCMeta, abstractmethod
  2. class Company():
  3. """
  4. 抽象公司类
  5. """
  6. __metaclass__ = ABCMeta
  7. def __init__(self, name):
  8. self.name = name
  9. @abstractmethod
  10. def add(self, c):
  11. """
  12. 通常用add来增加树枝或树叶
  13. """
  14. pass
  15. @abstractmethod
  16. def remove(self, c):
  17. """
  18. 通常用remove来删除树枝或树叶
  19. """
  20. pass
  21. @abstractmethod
  22. def display(self, depth):
  23. pass
  24. @abstractmethod
  25. def line_of_duty(self):
  26. pass
  27. class ConcreteCompany(Company):
  28. """
  29. 具体公司类
  30. """
  31. def __init__(self, name):
  32. super().__init__(name)
  33. self.children = []
  34. def add(self, c):
  35. self.children.append(c)
  36. def remove(self, c):
  37. self.children.remove(c)
  38. def display(self, depth):
  39. print("-"*depth, self.name)
  40. for c in self.children:
  41. c.display(depth+2)
  42. def line_of_duty(self):
  43. for c in self.children:
  44. c.line_of_duty()
  45. class HRDepartment(Company):
  46. """
  47. 人力资源部
  48. """
  49. def add(self, c):
  50. pass
  51. def remove(self, c):
  52. pass
  53. def display(self, depth):
  54. print("-"*depth, self.name)
  55. def line_of_duty(self):
  56. print("{}负责员工招聘。".format(self.name))
  57. class FinanceDepartment(Company):
  58. """
  59. 财务部
  60. """
  61. def add(self, c):
  62. pass
  63. def remove(self, c):
  64. pass
  65. def display(self, depth):
  66. print("-"*depth, self.name)
  67. def line_of_duty(self):
  68. print("{}负责财务收支。".format(self.name))
  69. def main():
  70. root = ConcreteCompany("北京总公司")
  71. root.add(HRDepartment("总公司人力资源部"))
  72. root.add(FinanceDepartment("总公司财务部"))
  73. comp = ConcreteCompany("上海华东分公司")
  74. comp.add(HRDepartment("华东分公司人力资源部"))
  75. comp.add(FinanceDepartment("华东分公司财务部"))
  76. root.add(comp)
  77. comp1 = ConcreteCompany("南京办事处")
  78. comp1.add(HRDepartment("南京办事处人力资源部"))
  79. comp1.add(FinanceDepartment("南京办事处财务部"))
  80. comp.add(comp1)
  81. comp2 = ConcreteCompany("杭州办事处")
  82. comp2.add(HRDepartment("杭州办事处人力资源部"))
  83. comp2.add(FinanceDepartment("杭州办事处财务部"))
  84. comp.add(comp2)
  85. print("组织架构图")
  86. root.display(1)
  87. print("履行职责")
  88. root.line_of_duty()
  89. main()
  1. 组织架构图
  2. - 北京总公司
  3. --- 总公司人力资源部
  4. --- 总公司财务部
  5. --- 上海华东分公司
  6. ----- 华东分公司人力资源部
  7. ----- 华东分公司财务部
  8. ----- 南京办事处
  9. ------- 南京办事处人力资源部
  10. ------- 南京办事处财务部
  11. ----- 杭州办事处
  12. ------- 杭州办事处人力资源部
  13. ------- 杭州办事处财务部
  14. 履行职责
  15. 总公司人力资源部负责员工招聘。
  16. 总公司财务部负责财务收支。
  17. 华东分公司人力资源部负责员工招聘。
  18. 华东分公司财务部负责财务收支。
  19. 南京办事处人力资源部负责员工招聘。
  20. 南京办事处财务部负责财务收支。
  21. 杭州办事处人力资源部负责员工招聘。
  22. 杭州办事处财务部负责财务收支。

点评

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

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

[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. String.getBytes()和String.tocharArray(),字节数组和字符数组的区别

    String.getBytes()是将字符串转化为一个字节数组.而String.toCharArray()是将一个字符串转化为一个字符数组. [例如] byte bys[] ="国庆60周年 ...

  2. Quratz的理解

    一:公共术语 1.为什么使用Qurztz 在某一个有规律的时间点干某件事.并且时间的触发的条件可以非常复杂(比如每月最后一个工作日的17:50),复杂到需要一个专门的框架来干这个事. Quartz就是 ...

  3. oracle的DBMS_JOB相关知识

    http://langgufu.iteye.com/blog/1179235 查看当前定时任务 select job,next_date,next_sec,failures,broken from u ...

  4. mniui里面没有只显示年的控件,monthpicker显示年月,datepicker显示具体到天的日期

    spinner无法出现下拉框,只能一下下的点击. combobox可以出现下拉框,但是一般情况是从url后台取值. 现在可以自己在js里定义需要的值. <td><input id=& ...

  5. 简单封装kafka相关的api

    一.针对于kafka版本 <dependency> <groupId>org.apache.kafka</groupId> <artifactId>ka ...

  6. Spark 常见问题集合

    一.Spark 为什么比 MapReduce 要高效? 举一个例子: select a.state,count(*),AVERAGE(c.price) from a join b on (a.id=b ...

  7. Vue proxyTable 解决开发环境的跨域问题

    在 config/index.js 配置文件中,添加 dev: { proxyTable: { '/ssp/withdraw': { target: 'http://dev.home.phiwifi. ...

  8. Android中,如何提升Layout的性能?

    Layout 是 Android 应用中直接影响用户体验的关键部分.如果实现的不好,你的 Layout 会导致程序非常占用内存并且 UI 运行缓慢.Android SDK 带有帮助你找到 Layout ...

  9. 潭州课堂25班:Ph201805201 django 项目 第四十五课 mysql集群和负载均衡(课堂笔记)

    2.使用docker安装Haproxy 一.为什么要使用数据库集群和负载均衡? 1.高可用 2.高并发 3.高性能 二.mysql数据库集群方式 三.使用docker安装PXC 1.拉取PXC镜像 d ...

  10. 潭州课堂25班:Ph201805201 爬虫高级 第十课 Scrapy-redis分布 (课堂笔记)

    利用 redis 数据库,做 request 队列,去重,多台数据共享, scrapy 调度 基于文件每户,默认只能在单机运行, scrapy-redis 默认把数据放到 redis 中,实现数据共享 ...