目录

  • 一、建造者模式
    • 问题描述
    • 问题分析
    • 模式定义
    • 代码实现
  • 二、观察者模式
    • 问题描述
    • 问题分析
    • 模式定义
    • 代码实现
  • 三、原型模式
    • 问题描述
    • 问题分析
    • 模式定义
    • 代码实现
  • 四、模板方法模式
    • 问题描述
    • 问题分析
    • 模式定义
    • 代码实现
  • 五、外观模式
    • 问题描述
  • 六、抽象工厂模式

工厂方法模式见Task02

一、建造者模式

问题描述

我的要求是你用程序画一个小人,这在游戏程序里非常常见,现在简单一点,要求是小人要有头、身体、两手、两脚就可以了。

问题分析

这里建造小人的’过程’是稳定的,都需要头身手脚,而具体建造的’细节’是不同的,有胖有瘦有高有矮。如果你需要将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示的意图时,我们需要应用于一个设计模式,‘建造者模式(Builder)’,又叫生成器模式。

模式定义

建造者模式(Builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

它主要用于创建一些复杂的对象,这些对象内部子对象的建造顺序通常是稳定的,但每个子对象本身的构建通常面临着复杂的变化。

代码实现

import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from matplotlib.patches import Ellipseclass PersonBuilder(object):def __init__(self, ax, color):self.ax = axself.color = colordef build_head(self):passdef build_body(self):passdef build_arm_left(self):passdef build_arm_right(self):passdef build_leg_left(self):passdef build_leg_right(self):passclass PersonFatBuilder(PersonBuilder):def build_head(self):self.ax.add_patch(Ellipse(xy=(50 + 15, -20 - 15), width=30, height=30, color=self.color))def build_body(self):self.ax.add_patch(Ellipse(xy=(45 + 20, -50 - 25), width=40, height=50, color=self.color))def build_arm_left(self):self.ax.add_patch(Line2D(xdata=(50, 30), ydata=(-50, -100), color=self.color))def build_arm_right(self):self.ax.add_patch(Line2D(xdata=(80, 100), ydata=(-50, -100), color=self.color))def build_leg_left(self):self.ax.add_patch(Line2D(xdata=(60, 45), ydata=(-100, -150), color=self.color))def build_leg_right(self):self.ax.add_patch(Line2D(xdata=(70, 85), ydata=(-100, -150), color=self.color))class PersonThinBuilder(PersonBuilder):def build_head(self):self.ax.add_patch(Ellipse(xy=(50 + 15, -20 - 15), width=30, height=30, color=self.color))def build_body(self):self.ax.add_patch(Ellipse(xy=(60 + 5, -50 - 50), width=10, height=50, color=self.color))def build_arm_left(self):self.ax.add_patch(Line2D(xdata=(60, 40), ydata=(-50, -100), color=self.color))def build_arm_right(self):self.ax.add_patch(Line2D(xdata=(70, 90), ydata=(-50, -100), color=self.color))def build_leg_left(self):self.ax.add_patch(Line2D(xdata=(60, 45), ydata=(-100, -150), color=self.color))def build_leg_right(self):self.ax.add_patch(Line2D(xdata=(70, 85), ydata=(-100, -150), color=self.color))# 指挥者
class PersonDirector(object):def __init__(self, pb):self.pb = pbdef create_person(self):self.pb.build_head()self.pb.build_body()self.pb.build_arm_left()self.pb.build_arm_right()self.pb.build_leg_left()self.pb.build_leg_right()plt.xlim((0, 150))plt.ylim((-150, 0))plt.axis("off")plt.show()if __name__ == '__main__':gThin = plt.figure(figsize=(8, 8))axThin = gThin.add_subplot(1, 1, 1)ptb = PersonThinBuilder(axThin, "k")pdThin = PersonDirector(ptb)pdThin.create_person()gFat = plt.figure(figsize=(8, 8))axFat = gFat.add_subplot(1, 1, 1)pfb = PersonFatBuilder(axFat, "k")pdFat = PersonDirector(pfb)pdFat.create_person()


二、观察者模式

问题描述

我们设想一个场景,假设公司几个同事日常喜欢工作摸鱼,有看 NBA 的,有炒股的,还有玩儿游戏的。但摸鱼肯定怕被自己领导或老板发现,怎么办呢?他们只好每隔几分钟就起来看看老板或者自己的领导有没有回来。这很不方便,想象一下,如果有几十个同事在摸鱼(这公司怕是要倒闭了),大家总不能跟赶集一样,隔几分钟就起来走几步吧。

此时,有人突拍大腿:为啥不整个吹哨人呢,比如前台小妹子?如果老板来了,她只需给我们发个微信消息通知一下就行了呀——有道理!先建个群把大家都拉进去,有领导来了就让前台小妹发消息。这下方便了,只要消息来了就知道是领导来了,赶紧采取行动。而且,如果这会儿突然不想摸鱼了,那把消息屏蔽了就行,明天又想摸鱼,把消息屏蔽取消就可以了。皆大欢喜。

问题分析

我们用观察者模式重新分析开始的问题,针对领导的群就是 Subject,员工则是 Observer,一个 Subject 可以有多个 Observer,它不需要关心到底有哪些 Observer,Observer 之间也不需要知道彼此存在。当 Subject 的状态发生变化(即领导回来)时,所有的 Observer 都会得到通知,并更新自己的行为(努力工作)。

当然,反过来一个 Observer 可以订阅多个 Subject,任意一个 Subject 的状态发生变化,该 Observer 都会得到通知。这样就既解决了一致性问题,又不会过紧耦合。

模式定义

观察者模式又叫作发布-订阅(Publish/Subscribe)模式。

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

  • Subject类,可翻译为主题或抽象通知者,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
  • Observer类,抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫作更新接口。抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个update()方法,这个方法叫作更新方法。
  • ConcreteSubject类,叫作具体主题或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
  • ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。

代码实现

class Observer(object):def __init__(self, name, sub):self.name = nameself.sub = subdef update(self):passclass Subject(object):subjectState = ""def attach(self, observer: Observer):passdef detach(self, observer: Observer):passdef notify(self):passclass StockObserver(Observer):def __init__(self, name, sub: Subject):super().__init__(name, sub)def update(self):print(" ".join([self.sub.subjectState, self.name, "关闭股票行情,继续工作!"]))class NBAObserver(Observer):def __init__(self, name, sub: Subject):super().__init__(name, sub)def update(self):print(" ".join([self.sub.subjectState, self.name, "关闭NBA直播,继续工作!"]))class Boss(Subject):__observers = []__action = ""def attach(self, observer):self.__observers.append(observer)def detach(self, observer):self.__observers.remove(observer)def notify(self):for each in self.__observers:each.update()def get_action(self):return self.__actiondef set_action(self, action):self.__action = actionsubjectState = property(get_action, set_action)class Secretary(Subject):__observers = []__action = ""def attach(self, observer):self.__observers.append(observer)def detach(self, observer):self.__observers.remove(observer)def notify(self):for each in self.__observers:each.update()def get_action(self):return self.__actiondef set_action(self, action):self.__action = actionsubjectState = property(get_action, set_action)if __name__ == '__main__':huhansan = Boss()coworker1 = StockObserver("魏关姹", huhansan)coworker2 = NBAObserver("易管查", huhansan)huhansan.attach(coworker1)huhansan.attach(coworker2)huhansan.detach(coworker1)# 老板回来huhansan.subjectState = "我胡汉三回来了!"# 发出通知huhansan.notify()

三、原型模式

问题描述

要求有一个简历类,必须要有姓名,可以设置性别和年龄,可以设置工作经历。最终我需要写三份简历。

问题分析

一般在初始化的信息不发生变化的情况下,克隆是最好的办法。这既隐藏了对象创建的细节,又对性能是大大的提高。

  • 浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
  • 深复制:深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。

模式定义

原型模式(Prototype),用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。

它不用重新初始化对象,而是动态地获得对象运行时的状态。

代码实现

import copyclass Prototype(object):def __init__(self):self._objects = {}def register(self, name, obj):self._objects[name] = objdef unregister(self, name):if name in self._objects:del self._objects[name]def clone(self, name, **kwargs):prototypeObj = self._objects.get(name)if not prototypeObj:raise ValueError("Incorrect object name")obj = copy.deepcopy(prototypeObj)obj.__dict__.update(kwargs)return objclass workExperience(object):__workDate = 0__company = 0def get_workDate(self):return self.__workDatedef set_workDate(self, workDate):self.__workDate = workDatedef get_company(self):return self.__companydef set_company(self, company):self.__company = companyworkDate = property(get_workDate, set_workDate)company = property(get_company, set_company)class Resume(object):def __init__(self, name):self.name = nameself.work = workExperience()def setPersonalInfo(self, sex, age):self.sex = sexself.age = agedef setWorkExperience(self, timeArea, company):self.work.workDate = timeAreaself.work.company = companydef display(self):print(" ".join([self.name, self.sex, self.age]))print(" ".join(["工作经历:", self.work.workDate, self.work.company]))if __name__ == '__main__':prototype = Prototype()a = Resume('大鸟')a.setPersonalInfo('男', '29')a.setWorkExperience('1998-2000', 'XX公司')prototype.register('a', a)b = prototype.clone('a')b.setWorkExperience('1998-2006', 'YY企业')c = prototype.clone('a')c.setPersonalInfo('男', '24')c.setWorkExperience('1998-2003', 'ZZ企业')a.display()b.display()c.display()

四、模板方法模式

问题描述

题目抄错了,那就不是考试题目了,而考试试卷最大的好处就是,大家都是一样的题目,特别是标准化的考试,比如全是选择或判断的题目,那就最大化地限制了答题者的发挥,大家都是ABCD或打钩打叉,非对即错的结果。这其实就是一个典型的设计模式。

问题分析

既然用了继承,并且肯定这个继承有意义,就应该要成为子类的模板,所有重复的代码都应该要上升到父类去,而不是让每个子类都去重复。

模板方法登场了,当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。

模式定义

模板方法(Template Method)模式,定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

模板方法模式是通过把不变行为搬移到超类,去除子类中的重复代码来体现它的优势。

当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。我们通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。

代码实现

# 金庸小说考题试卷
class TestPaper(object):def testQuestion1(self):print("杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] a.球墨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维")print("答案:" + self.Answer1())def testQuestion2(self):print("杨过、程英、陆无双铲除了情花,造成[ ] a.使这种植物不再害人 b.使一种珍稀物种灭绝了 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化")print("答案:" + self.Answer2())def testQuestion3(self):print("蓝凤凰致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ] a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量的生牛奶 e.以上全不对")print("答案:" + self.Answer3())def Answer1(self):return ""def Answer2(self):return ""def Answer3(self):return ""class TestPaperA(TestPaper):def Answer1(self):return "b"def Answer2(self):return "c"def Answer3(self):return "a"class TestPaperB(TestPaper):def Answer1(self):return "c"def Answer2(self):return "a"def Answer3(self):return "a"if __name__ == '__main__':print("学生甲抄的试卷:")studentA = TestPaperA()studentA.testQuestion1()studentA.testQuestion2()studentA.testQuestion3()print("学生乙抄的试卷:")studentB = TestPaperB()studentB.testQuestion1()studentB.testQuestion2()studentB.testQuestion3()

五、外观模式

问题描述

六、抽象工厂模式

大话设计模型 Task03:工厂、制造、观察相关推荐

  1. 大话设计模型 Task02:策略、装饰、代理

    目录 一.简单工厂模式 问题描述 模式定义 问题分析 代码实现 二.策略模式 问题描述 问题分析 模式定义 代码实现 三.装饰模式 问题描述 问题分析 模式定义 代码实现 四.代理模式 问题描述 问题 ...

  2. 我的设计模型之简单工厂

    抽象工厂模型 了解设计模型的人都该清楚啊 代码自己打一下 比较清楚啊 using System; using System.Collections.Generic; using System.Linq ...

  3. 装箱---一个工厂制造的产品形状都是长方体,它们的高度都是 h,长和宽都相等,一共有六个型号,他们的长宽分别为 1*1, 2*2, 3*3, 4*4, 5*5, 6*6.

    问题描述 一个工厂制造的产品形状都是长方体,它们的高度都是 h,长和宽都相等,一共有六个型号,他们的长宽分别为 1*1, 2*2, 3*3, 4*4, 5*5, 6*6.  这些产品通常使用一个  6 ...

  4. 案例分析 | 宜家以双钻设计模型探索线上零售新业务

    2022年宜家陆续关闭中国2家线下门店,原因是中国业务战略调整还是疫情环境线下门店客流压力转型线上业务?根据宜家2021财年业绩报告,在全球供应链曾中断背景下,宜家疫情期间逆势增长,其中线上收入增速同 ...

  5. ai css 线条粗细_如何训练AI将您的设计模型转换为HTML和CSS

    ai css 线条粗细 by Emil Wallner 埃米尔·沃尔纳(Emil Wallner) 如何训练AI将您的设计模型转换为HTML和CSS (How you can train an AI ...

  6. R语言计算回归模型每个样本(观察、observation、sample)的DFFITS度量实战:忽略单个观察(样本)时,回归模型所做的预测会发生多大的变化

    R语言计算回归模型每个样本(观察.observation.sample)的DFFITS度量实战:忽略单个观察(样本)时,回归模型所做的预测会发生多大的变化 目录

  7. R语言计算回归模型每个样本(观察、observation、sample)的杠杆值(leverage)实战:如果一个样本的预测变量比其他样本的预测变量值更极端,那么被认为具有很高的杠杆作用

    R语言计算回归模型每个样本(观察.observation.sample)的杠杆值(leverage)实战:如果一个样本的预测变量比其他样本的预测变量值更极端,那么被认为具有很高的杠杆作用 目录

  8. R语言计算回归模型每个样本(观察、observation、sample)的DFBETAS值实战:每一个样本对给定系数的估计有多大的影响

    R语言计算回归模型每个样本(观察.observation.sample)的DFBETAS值实战:每一个样本对给定系数的估计有多大的影响 目录

  9. Django框架(3.django设计模型类、模型类生成表、ORM框架简介)

    ORM框架简介 O是object,也就类对象的意思, R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思, M是mapping,是映射的意思.在ORM框架中,它帮我们把类和数据表进 ...

最新文章

  1. 迁移学习之ResNet50和ResNet101(图像识别)
  2. 《强化学习周刊》第29期:Atari 深度强化学习的研究综述、金融强化学习的最新进展...
  3. android apk获取权限,Android apk 获取系统权限的方式
  4. 字符串%百分号 和 format 格式化
  5. sqlserver 2008r2 执行代码 快捷键
  6. 解释一下为什么数据文件最好采用单字符作为字段分隔符
  7. 自定义django表单
  8. html实现颜色色板,JS实现的系统调色板完整实例
  9. 疯狂软件Oracle数据库视频
  10. redis的基本命令
  11. windows10 LTSC转换成pro
  12. 小米手机开启开发者模式的步骤与方法
  13. 武魂java_js及jsp.java查错的几种方式
  14. 2022年淘宝618活动时间和天猫618有什么优惠活动
  15. NKOI 1905 慢跑小路
  16. 关于ERP系统,你可能不知道的10件事
  17. judgement_mna_2016
  18. Dell 工作站故障诊断报警信息原因查询
  19. 机器人 机械臂右手定则
  20. 新智元【Yoshua Bengio 亲自解答】机器学习 81 个问题及答案(最全收录)

热门文章

  1. 骑驴找马被察觉怎么办?
  2. 常见文件的加密工具类
  3. RoadFlow ASP.NET Core工作流配置文件说明
  4. 删除Windows.old提示需要TrustInstaller权限
  5. Ubuntu18.04离线安装Intel I219-V网卡驱动解决有线网络无法连接网卡不识别的问题
  6. 关于极域的那些事------学生机连不上教师机
  7. 三大场景、四大趋势:平安区块链平台与金融壹账通的实践总结
  8. dpkg-deb: error: paste subprocess was killed by signal (Broken pipe)
  9. CAT ----分布式实时监控系统
  10. 手机中电容屏和电阻屏有什么区别?