[Python设计模式] 第19章 分公司=部门?——组合模式
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章 分公司=部门?——组合模式的更多相关文章
- [Python设计模式] 第1章 计算器——简单工厂模式
github地址:https://github.com/cheesezh/python_design_patterns 写在前面的话 """ 读书的时候上过<设计模 ...
- [Python设计模式] 第13章 造小人——建造者模式
github地址:https://github.com/cheesezh/python_design_patterns 题目1 用程序模拟一个画小人的过程,要求小人要有头,身子,左手,右手,左脚,右脚 ...
- javascript设计模式(张容铭) 第14章 超值午餐-组合模式 学习笔记
JS 组合模式更常用于创建表单上,比如注册页面可能有不同的表单提交模块.对于这些需求我们只需要有基本的个体,然后通过一定的组合即可实现,比如下面这个页面样式(如图14-2所示),我们来用组合模式实现. ...
- 设计模式(九):Composite组合模式 -- 结构型模式
1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 我们可以使用简单的对象组合成复杂的对象,而这个复杂对 ...
- 【设计模式】学习笔记13:组合模式(Composite)
本文出自 http://blog.csdn.net/shuangde800 认识组合模式 上一篇中,我们可以用迭代器来实现遍历一个集合(数组,ArrayList, Vector, HashTabl ...
- Java设计模式偷跑系列(十二)组合模式建模和实现
转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39828653 组合模式(Composite):组合模式有时又叫部分-总体模式.将对象组合成 ...
- [Python设计模式] 第21章 计划生育——单例模式
github地址:https://github.com/cheesezh/python_design_patterns 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式 ...
- [Python设计模式] 第26章 千人千面,内在共享——享元模式
github地址:https://github.com/cheesezh/python_design_patterns 背景 有6个客户想做产品展示网站,其中3个想做成天猫商城那样的"电商风 ...
- [Python设计模式] 第22章 手机型号&软件版本——桥接模式
github地址:https://github.com/cheesezh/python_design_patterns 紧耦合程序演化 题目1 编程模拟以下情景,有一个N品牌手机,在上边玩一个小游戏. ...
随机推荐
- 069 在SparkStreaming的窗口分析
一:说明 1.图例说明 ---------------------------------------------------------------------------------------- ...
- quratz数据存储
Quartz 中的 trigger 和 job 需要存储下来才能被使用. 1.两种存储方式 RAMJobStore, JobStoreSupport, 其中 RAMJobStore 是将 trigge ...
- Spring(二)IOC底层实现原理
IOC原理 将对象创建交给Spring去管理. 实现IOC的两种方式 IOC配置文件的方式 IOC注解的方式 IOC底层实现原理 底层实现使用的技术 1.1 xml配置文件 1.2 dom4j解析xm ...
- Stm32串口通信(USART)
Stm32串口通信(UART) 串口通信的分类 串口通信三种传递方式 串口通信的通信方式 串行通信的方式: 异步通信:它用一个起始位表示字符的开始,用停止位表示字符的结束.其每帧的格式如下: 在一帧格 ...
- Ef 自动迁移,日志
Ef 迁移 在vs打开程序控制台 2,选择程序集 ,如果是初次,输入 Enable-Migrations,启动迁徙 3 添加迁移,完成修改 4,之后会自动生成迁移配置文件. 然后再上下文类中加入 两 ...
- MySQL数据库基本用法-聚合-分组
聚合 为了快速得到统计数据,提供了5个聚合函数 count(*)表示计算总行数,括号中写星与列名,结果是相同的 查询学生总数 select count(*) from students; max(列) ...
- Unity IOC容器的构造函数使用笔记(不能错过的Unity示例)
示例一,正常使用: 相关定义: public interface ICar { int Run(); } public class BMW : ICar { ; public int Run() { ...
- node安装及配置之windows版
一.下载地址 https://nodejs.org/zh-cn/download/ https://nodejs.org/zh-cn/download/releases/ 二.安装步骤 1.双击“no ...
- 深入理解arguments.callee
在函数内部,有两个特殊的对象:arguments 和 this.其中, arguments 的主要用途是保存函数参数, 但这个对象还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 a ...
- 网上的很多Android项目源码有用吗?Android开发注意的地方。
在Android项目开发中,我们可以在网上看到很多项目源码,大部分也不是很精致, 比如 06.Android阿福多媒体播放器开发教程+源码 还有什么浏览器源码. 那么这些有用吗? 价值在哪里? 精致 ...