[Python设计模式] 第9章 如何准备多份简历——原型模式
github地址:https://github.com/cheesezh/python_design_patterns
题目
设计一个简历类,必须有姓名,可以设置性别和年龄,即个人信息,可以设置曾就职公司和工作时间,即工作经历。
基础版本
class Resume():
def __init__(self, name):
self.name = name # python默认成员变量公开
self.__sex = None # python默认成员变量公开,加__表示私有
self.__age = None # python默认成员变量公开,加__表示私有
self.__time_area = None # python默认成员变量公开,加__表示私有
self.__company = None # python默认成员变量公开,加__表示私有
def set_personal_info(self, sex, age):
self.__sex = sex
self.__age = age
def set_work_experience(self, time_area, company):
self.__time_area = time_area
self.__company = company
def display(self):
print("{}\t{}\t{}".format(self.name, self.__sex, self.__age))
print("{}\t{}".format(self.__time_area, self.__company))
def main():
resume_a = Resume("鸣人")
resume_a.set_personal_info("男", "29")
resume_a.set_work_experience("2016-2018", "木叶公司")
resume_b = Resume("鸣人")
resume_b.set_personal_info("男", "29")
resume_b.set_work_experience("2016-2018", "木叶公司")
resume_c = Resume("鸣人")
resume_c.set_personal_info("男", "29")
resume_c.set_work_experience("2016-2018", "木叶公司")
resume_a.display()
resume_b.display()
resume_c.display()
main()
鸣人 男 29
2016-2018 木叶公司
鸣人 男 29
2016-2018 木叶公司
鸣人 男 29
2016-2018 木叶公司
点评
- 上述main函数中生成简历的方法,相当于手写简历,三份简历要三次实例化
- 而且如果要更改某个字段,比如把时间从
2016-2018
改成2017-2018
,那么同样修改三次
那如果这样写呢?
def main():
resume_a = Resume("鸣人")
resume_a.set_personal_info("男", "29")
resume_a.set_work_experience("2016-2018", "木叶公司")
resume_b = resume_a
resume_c = resume_a
resume_a.display()
resume_b.display()
resume_c.display()
main()
鸣人 男 29
2016-2018 木叶公司
鸣人 男 29
2016-2018 木叶公司
鸣人 男 29
2016-2018 木叶公司
点评
- 这里传递的是引用,而不是具体的值,相当于在简历b和简历c上没有实际内容,而是写着“详见简历a”
- 可以使用clone的方法解决这个问题,即原型模式
原型模式
原型模式,即用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象[DP]。也就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
from abc import ABCMeta, abstractmethod
from copy import copy
class Prototype():
"""
抽象原型类
"""
__metaclass__ = ABCMeta
def __init__(self, id):
self.id = id
@abstractmethod
def clone(self):
pass
class ConcretePrototypeOne(Prototype):
"""
具体原型类
"""
def __init__(self, id):
super().__init__(id)
def clone(self):
return copy(self) # 1. 浅拷贝copy.copy() 或 深拷贝copy.deepcopy() 2. Python无需强制类型转换
def main():
prototype1 = ConcretePrototypeOne("1")
prototype1_cloned = prototype1.clone()
print(prototype1_cloned.id)
main()
1
Python中的浅拷贝与深拷贝
Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块。
- copy.copy(浅拷贝):只拷贝顶层对象,不会拷贝顶层对象的内部的对象成员变量;
- copy.deepcopy(深拷贝):拷贝对象及其子对象
按照基础版本的简历类定义,成员变量的类型都是基本数据类型(string),所以使用浅拷贝即可。那么什么时候用深拷贝呢?假如我们将工作经历定义为一个单独的类WorkExperience,那么简历类中就会有一个成员变量的类型是WorkExperience,如果这时候需要拷贝操作,就需要用深拷贝了。
深拷贝原型模式
from copy import deepcopy
class WorkExperience():
def __init__(self, time_area="", company=""):
self.time_area = time_area
self.company = company
class Resume():
def __init__(self, name):
self.name = name # python默认成员变量公开
self.__sex = None # python默认成员变量公开,加__表示私有
self.__age = None # python默认成员变量公开,加__表示私有
self.__work_expereince = WorkExperience() # python默认成员变量公开,加__表示私有
def set_personal_info(self, sex, age):
self.__sex = sex
self.__age = age
def set_work_experience(self, time_area, company):
self.__work_expereince.time_area = time_area
self.__work_expereince.company = company
def display(self):
print("{}\t{}\t{}".format(self.name, self.__sex, self.__age))
print("{}\t{}".format(self.__work_expereince.time_area, self.__work_expereince.company))
def deep_clone(self):
"""
深拷贝方法
"""
return deepcopy(self)
def clone(self):
"""
浅拷贝方法
"""
return copy(self)
def main():
resume_a = Resume("鸣人")
resume_a.set_personal_info("男", "29")
resume_a.set_work_experience("2016-2018", "木叶公司")
resume_b = resume_a.clone()
resume_b.set_work_experience("2018-2019", "王者学校")
resume_c = resume_a.clone()
resume_c.set_personal_info("男", "24")
resume_c.set_work_experience("2019-2020", "问问公司")
resume_a.display()
resume_b.display()
resume_c.display()
def deep_main():
resume_a = Resume("鸣人")
resume_a.set_personal_info("男", "29")
resume_a.set_work_experience("2016-2018", "木叶公司")
resume_b = resume_a.deep_clone()
resume_b.set_work_experience("2018-2019", "王者学校")
resume_c = resume_a.deep_clone()
resume_c.set_personal_info("男", "24")
resume_c.set_work_experience("2019-2020", "问问公司")
resume_a.display()
resume_b.display()
resume_c.display()
print("---浅拷贝, 工作经历都被修改成最后一次的值---")
main()
print("--------深拷贝, 工作经历为不同的值--------")
deep_main()
---浅拷贝, 工作经历都被修改成最后一次的值---
鸣人 男 29
2019-2020 问问公司
鸣人 男 29
2019-2020 问问公司
鸣人 男 24
2019-2020 问问公司
--------深拷贝, 工作经历为不同的值--------
鸣人 男 29
2016-2018 木叶公司
鸣人 男 29
2018-2019 王者学校
鸣人 男 24
2019-2020 问问公司
[Python设计模式] 第9章 如何准备多份简历——原型模式的更多相关文章
- [Python设计模式] 第7章 找人帮忙追美眉——代理模式
github地址:https://github.com/cheesezh/python_design_patterns 题目1 Boy追求Girl,给Girl送鲜花,送巧克力,送洋娃娃. class ...
- [Python设计模式] 第15章 如何兼容各种DB——抽象工厂模式
github地址:https://github.com/cheesezh/python_design_patterns 题目 如何让一个程序,可以灵活替换数据库? 基础版本 class User(): ...
- 2.6 《硬啃设计模式》第8章 复制不是很难 - 原型模式(Prototype Pattern)
案例: 某即时战略游戏,你训练出来各种很强的战士. 为了增加游戏的可玩性,增加了一种复制魔法.实施该魔法,可以复制任意的战士. 你会怎样考虑这个设计? 在继续阅读之前,请先认真思考并写出你的设计,这样 ...
- [Python设计模式] 第21章 计划生育——单例模式
github地址:https://github.com/cheesezh/python_design_patterns 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式 ...
- [Python设计模式] 第1章 计算器——简单工厂模式
github地址:https://github.com/cheesezh/python_design_patterns 写在前面的话 """ 读书的时候上过<设计模 ...
- [Python设计模式] 第22章 手机型号&软件版本——桥接模式
github地址:https://github.com/cheesezh/python_design_patterns 紧耦合程序演化 题目1 编程模拟以下情景,有一个N品牌手机,在上边玩一个小游戏. ...
- [Python设计模式] 第28章 男人和女人——访问者模式
github地址:https://github.com/cheesezh/python_design_patterns 题目 用程序模拟以下不同情况: 男人成功时,背后多半有一个伟大的女人: 女人成功 ...
- [Python设计模式] 第26章 千人千面,内在共享——享元模式
github地址:https://github.com/cheesezh/python_design_patterns 背景 有6个客户想做产品展示网站,其中3个想做成天猫商城那样的"电商风 ...
- [Python设计模式] 第27章 正则表达式——解释器模式
github地址:https://github.com/cheesezh/python_design_patterns 解释器模式 解释器模式,给定一个语言,定一个它的文法的一种表示,并定一个一个解释 ...
随机推荐
- 使用siege执行压力测试
没有安装siege? 可参考我的另一篇博客 使用siege执行压力测试笔记 场景分析 使用siege对https://www.baidu.com/进行加压. 要求 模拟20个用户同时访问 一共跑3个循 ...
- python 全栈开发,Day116(可迭代对象,type创建动态类,偏函数,面向对象的封装,获取外键数据,组合搜索,领域驱动设计(DDD))
昨日内容回顾 1. 三个类 ChangeList,封装列表页面需要的所有数据. StarkConfig,生成URL和视图对应关系 + 默认配置 AdminSite,用于保存 数据库类 和 处理该类的对 ...
- python 全栈开发,Day104(DRF用户认证,结算中心,django-redis)
考试第二部分:MySQL数据库 6. MySQL中char和varchar的区别(1分) char是定长,varchar是变长. char的查询速度比varchar要快. 7. MySQL中va ...
- 步步为营-10-string的简单操作
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Tex ...
- Oracle中数值的计算
运算符 含义 · +(加) 加法 · ||(加) 字符串相加 · -(减) 减法 · *(乘) 乘法 · /(除) 除法 · mod(模)返回一个除法的整数余数 例如,12 % 5 ...
- git代码提交步骤,教程
代码提交 代码提交一般有五个步骤: 1.查看目前代码的修改状态 2.查看代码修改内容 3.暂存需要提交的文件 4.提交已暂存的文件 5.同步到服务器 1. 查看目前代码的修改状态 提交代码之前 ...
- 《剑指offer》-双栈实现队列
题目描述 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 很基本的STL容器操作了,应该可以1A的,但是忘记返回值的时候,clang的报错感觉并不友好啊.. cl ...
- .NetCore 下开发独立的(RPL)含有界面的组件包 (一)准备工作
.NetCore 下开发独立的(RPL)含有界面的组件包 (一)准备工作 .NetCore 下开发独立的(RPL)含有界面的组件包 (二)扩展中间件及服 务 .NetCore 下开发独立的(RPL)含 ...
- java快速排序引起的StackOverflowError异常
写在前面:这篇随笔主要记录一下递归调用引起的虚拟机栈溢出的情况以及通过参数配置了虚拟机栈大小来使递归调用可以顺利执行.并没有对涉及到的一些概念进行详细的解释(因为我自己目前对这些概念并不是特别清楚), ...
- [转] 学会fetch的用法
fetch是web提供的一个可以获取异步资源的api,目前还没有被所有浏览器支持,它提供的api返回的是Promise对象,所以你在了解这个api前首先得了解Promise的用法.参考阮老师的文章 那 ...