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. SPOJ LCS2 - Longest Common Substring II 字符串 SAM

    原文链接http://www.cnblogs.com/zhouzhendong/p/8982484.html 题目传送门 - SPOJ LCS2 题意 求若干$(若干<10)$个字符串的最长公共 ...

  2. springmvc 无法访问静态资源

    没有配置<mvc:resources location="/" mapping="/**"/> <?xml version="1.0 ...

  3. 最终一致性2PC复杂场景,事务报数据库操作超时。

    稀里糊涂的,忘了开启SqlServer的is read committed snapshot on

  4. python-飞机大战

    效果图 main.py import time import pygame from EnemyPlane import EnemyPlane from HeroPlane import HeroPl ...

  5. 使用IntelliJ IDEA和Eclipse导入Github项目

    使用IntelliJ IDEA导入Github项目 菜单栏File->Settings->分别配置好Github和Git的相关信息,配置完之后点击旁边的Test按键可以查看是否配置成功 配 ...

  6. Django的MVT模型

    MVC模型和MVT模型 MVC简介: MVC的全拼为Model-View-Controller,最早由TrygveReenskaug在1978年提出,是施乐帕罗奥多研究中心(Xerox PARC)在2 ...

  7. linux 学习笔记六 tail 命令

    #tail -f -n100 catalina.out 含义 从文件尾部监视catalina.out 文件   要看文件尾部100行 #tail -f -n100  catalina,out > ...

  8. Xamarin Essentials教程数据传输DataTransfer

    Xamarin Essentials教程数据传输DataTransfer   通过数据传输功能,应用程序可以将文本或网址发送到其它的应用程序,这样就可以在应用程序之间共享数据,实现常见的分享功能.Xa ...

  9. Java笔记(十六)并发容器

    并发容器 一.写时复制的List和Set CopyOnWrite即写时复制,或称写时拷贝,是解决并发问题的一种重要思路. 一)CopyOnWriteArrayList 该类实现了List接口,它的用法 ...

  10. tomcat修改端口号

    以前只知道当tomcat端口号冲突了如何修改tomcat默认的8080端口号 今天遇到个情况,装了个BO,自带个tomcat,这时就需要修改三个地方 修改Tomcat的端口号: 在默认情况下,tomc ...