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

题目

设计一个简历类,必须有姓名,可以设置性别和年龄,即个人信息,可以设置曾就职公司和工作时间,即工作经历。

基础版本

  1. class Resume():
  2. def __init__(self, name):
  3. self.name = name # python默认成员变量公开
  4. self.__sex = None # python默认成员变量公开,加__表示私有
  5. self.__age = None # python默认成员变量公开,加__表示私有
  6. self.__time_area = None # python默认成员变量公开,加__表示私有
  7. self.__company = None # python默认成员变量公开,加__表示私有
  8. def set_personal_info(self, sex, age):
  9. self.__sex = sex
  10. self.__age = age
  11. def set_work_experience(self, time_area, company):
  12. self.__time_area = time_area
  13. self.__company = company
  14. def display(self):
  15. print("{}\t{}\t{}".format(self.name, self.__sex, self.__age))
  16. print("{}\t{}".format(self.__time_area, self.__company))
  17. def main():
  18. resume_a = Resume("鸣人")
  19. resume_a.set_personal_info("男", "29")
  20. resume_a.set_work_experience("2016-2018", "木叶公司")
  21. resume_b = Resume("鸣人")
  22. resume_b.set_personal_info("男", "29")
  23. resume_b.set_work_experience("2016-2018", "木叶公司")
  24. resume_c = Resume("鸣人")
  25. resume_c.set_personal_info("男", "29")
  26. resume_c.set_work_experience("2016-2018", "木叶公司")
  27. resume_a.display()
  28. resume_b.display()
  29. resume_c.display()
  30. main()
  1. 鸣人 29
  2. 2016-2018 木叶公司
  3. 鸣人 29
  4. 2016-2018 木叶公司
  5. 鸣人 29
  6. 2016-2018 木叶公司

点评

  • 上述main函数中生成简历的方法,相当于手写简历,三份简历要三次实例化
  • 而且如果要更改某个字段,比如把时间从2016-2018改成2017-2018,那么同样修改三次

那如果这样写呢?

  1. def main():
  2. resume_a = Resume("鸣人")
  3. resume_a.set_personal_info("男", "29")
  4. resume_a.set_work_experience("2016-2018", "木叶公司")
  5. resume_b = resume_a
  6. resume_c = resume_a
  7. resume_a.display()
  8. resume_b.display()
  9. resume_c.display()
  10. main()
  1. 鸣人 29
  2. 2016-2018 木叶公司
  3. 鸣人 29
  4. 2016-2018 木叶公司
  5. 鸣人 29
  6. 2016-2018 木叶公司

点评

  • 这里传递的是引用,而不是具体的值,相当于在简历b和简历c上没有实际内容,而是写着“详见简历a”
  • 可以使用clone的方法解决这个问题,即原型模式

原型模式

原型模式,即用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象[DP]。也就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。

  1. from abc import ABCMeta, abstractmethod
  2. from copy import copy
  3. class Prototype():
  4. """
  5. 抽象原型类
  6. """
  7. __metaclass__ = ABCMeta
  8. def __init__(self, id):
  9. self.id = id
  10. @abstractmethod
  11. def clone(self):
  12. pass
  13. class ConcretePrototypeOne(Prototype):
  14. """
  15. 具体原型类
  16. """
  17. def __init__(self, id):
  18. super().__init__(id)
  19. def clone(self):
  20. return copy(self) # 1. 浅拷贝copy.copy() 或 深拷贝copy.deepcopy() 2. Python无需强制类型转换
  21. def main():
  22. prototype1 = ConcretePrototypeOne("1")
  23. prototype1_cloned = prototype1.clone()
  24. print(prototype1_cloned.id)
  25. main()
  1. 1

Python中的浅拷贝与深拷贝

Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块。

  • copy.copy(浅拷贝):只拷贝顶层对象,不会拷贝顶层对象的内部的对象成员变量;
  • copy.deepcopy(深拷贝):拷贝对象及其子对象

按照基础版本的简历类定义,成员变量的类型都是基本数据类型(string),所以使用浅拷贝即可。那么什么时候用深拷贝呢?假如我们将工作经历定义为一个单独的类WorkExperience,那么简历类中就会有一个成员变量的类型是WorkExperience,如果这时候需要拷贝操作,就需要用深拷贝了。

深拷贝原型模式

  1. from copy import deepcopy
  2. class WorkExperience():
  3. def __init__(self, time_area="", company=""):
  4. self.time_area = time_area
  5. self.company = company
  6. class Resume():
  7. def __init__(self, name):
  8. self.name = name # python默认成员变量公开
  9. self.__sex = None # python默认成员变量公开,加__表示私有
  10. self.__age = None # python默认成员变量公开,加__表示私有
  11. self.__work_expereince = WorkExperience() # python默认成员变量公开,加__表示私有
  12. def set_personal_info(self, sex, age):
  13. self.__sex = sex
  14. self.__age = age
  15. def set_work_experience(self, time_area, company):
  16. self.__work_expereince.time_area = time_area
  17. self.__work_expereince.company = company
  18. def display(self):
  19. print("{}\t{}\t{}".format(self.name, self.__sex, self.__age))
  20. print("{}\t{}".format(self.__work_expereince.time_area, self.__work_expereince.company))
  21. def deep_clone(self):
  22. """
  23. 深拷贝方法
  24. """
  25. return deepcopy(self)
  26. def clone(self):
  27. """
  28. 浅拷贝方法
  29. """
  30. return copy(self)
  31. def main():
  32. resume_a = Resume("鸣人")
  33. resume_a.set_personal_info("男", "29")
  34. resume_a.set_work_experience("2016-2018", "木叶公司")
  35. resume_b = resume_a.clone()
  36. resume_b.set_work_experience("2018-2019", "王者学校")
  37. resume_c = resume_a.clone()
  38. resume_c.set_personal_info("男", "24")
  39. resume_c.set_work_experience("2019-2020", "问问公司")
  40. resume_a.display()
  41. resume_b.display()
  42. resume_c.display()
  43. def deep_main():
  44. resume_a = Resume("鸣人")
  45. resume_a.set_personal_info("男", "29")
  46. resume_a.set_work_experience("2016-2018", "木叶公司")
  47. resume_b = resume_a.deep_clone()
  48. resume_b.set_work_experience("2018-2019", "王者学校")
  49. resume_c = resume_a.deep_clone()
  50. resume_c.set_personal_info("男", "24")
  51. resume_c.set_work_experience("2019-2020", "问问公司")
  52. resume_a.display()
  53. resume_b.display()
  54. resume_c.display()
  55. print("---浅拷贝, 工作经历都被修改成最后一次的值---")
  56. main()
  57. print("--------深拷贝, 工作经历为不同的值--------")
  58. deep_main()
  1. ---浅拷贝, 工作经历都被修改成最后一次的值---
  2. 鸣人 29
  3. 2019-2020 问问公司
  4. 鸣人 29
  5. 2019-2020 问问公司
  6. 鸣人 24
  7. 2019-2020 问问公司
  8. --------深拷贝, 工作经历为不同的值--------
  9. 鸣人 29
  10. 2016-2018 木叶公司
  11. 鸣人 29
  12. 2018-2019 王者学校
  13. 鸣人 24
  14. 2019-2020 问问公司

[Python设计模式] 第9章 如何准备多份简历——原型模式的更多相关文章

  1. [Python设计模式] 第7章 找人帮忙追美眉——代理模式

    github地址:https://github.com/cheesezh/python_design_patterns 题目1 Boy追求Girl,给Girl送鲜花,送巧克力,送洋娃娃. class ...

  2. [Python设计模式] 第15章 如何兼容各种DB——抽象工厂模式

    github地址:https://github.com/cheesezh/python_design_patterns 题目 如何让一个程序,可以灵活替换数据库? 基础版本 class User(): ...

  3. 2.6 《硬啃设计模式》第8章 复制不是很难 - 原型模式(Prototype Pattern)

    案例: 某即时战略游戏,你训练出来各种很强的战士. 为了增加游戏的可玩性,增加了一种复制魔法.实施该魔法,可以复制任意的战士. 你会怎样考虑这个设计? 在继续阅读之前,请先认真思考并写出你的设计,这样 ...

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

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

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

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

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

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

  7. [Python设计模式] 第28章 男人和女人——访问者模式

    github地址:https://github.com/cheesezh/python_design_patterns 题目 用程序模拟以下不同情况: 男人成功时,背后多半有一个伟大的女人: 女人成功 ...

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

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

  9. [Python设计模式] 第27章 正则表达式——解释器模式

    github地址:https://github.com/cheesezh/python_design_patterns 解释器模式 解释器模式,给定一个语言,定一个它的文法的一种表示,并定一个一个解释 ...

随机推荐

  1. poj1195二维树状数组模板

    二维树状数组和一维的也差不多,改一下add和query函数即可:即按行修改,行内单点修改即可 /* 二维树状数组,询问一个二维区间内的数之和 */ #include<iostream> # ...

  2. [转] Sublime Text3 配置 NodeJs 环境

    前言 大家都知道,Sublime Text 安装插件一般从 Package Control 中直接安装即可,当我安装 node js 插件时候,直接通过Package Control 安装,虽然插件安 ...

  3. [ZJOI2006]书架

    链接:https://www.luogu.org/problemnew/show/P2596 题解: 写了两天的平衡树终于大概弄好了所有模板(模板不熟写错debug真是要死) 对于放在头尾,只需要删除 ...

  4. BZOJ1965 [Ahoi2005]SHUFFLE 洗牌 快速幂

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1965 题意概括 对于扑克牌的一次洗牌是这样定义的,将一叠N(N为偶数)张扑克牌平均分成上下两叠,取 ...

  5. 040 关于hive元数据的解析

    一:原理 1.整体原理 找到数据库 找到表 先找分区表,然后不找SDS表了,先去找PARTITIONS表,根据这张表的SD_ID找对应的HDFS路劲 再普通表,直接根据SDS表的中SD_ID找到对应的 ...

  6. Unity 中几点注意的地方

    1.面板摆放的规范 2.project工程面板中 文件夹命名的规范,不同类型的东西要分类摆放,例如Script 3.不要留空函数体(系统自动生成Start, Uadate等),空函数体一样会执行,尤其 ...

  7. 附005.Docker Compose文件详解

    一 Docker Compose文件简介 compose文件使用yml格式,主要分为了四个区域: version:用于指定当前docker-compose.yml语法遵循哪个版本 services:服 ...

  8. Spring框架学习03——Spring Bean 的详解

    1.Bean 的配置 Spring可以看做一个大型工厂,用于生产和管理Spring容器中的Bean,Spring框架支持XML和Properties两种格式的配置文件,在实际开发中常用XML格式的配置 ...

  9. Xamarin.Android部署失败

    Xamarin.Android部署失败   项目编译.生成没有错误信息,并且可以找到生成的APK包,但部署失败.提示信息如下: "apksigner.BAT"已退出,代码为1.   ...

  10. BZOJ.4319.[cerc2008]Suffix reconstruction(后缀数组 构造 贪心)

    题目链接 \(Description\) 给定SA数组,求满足SA[]的一个原字符串(每个字符为小写字母),无解输出-1. \(Solution\) 假设我们现在有suf(SA[j]),要构造suf( ...