大话设计模型 Task03:工厂、制造、观察
创始人
2024-04-26 18:55:52
0

目录

  • 一、建造者模式
    • 问题描述
    • 问题分析
    • 模式定义
    • 代码实现
  • 二、观察者模式
    • 问题描述
    • 问题分析
    • 模式定义
    • 代码实现

一、建造者模式

在这里插入图片描述

问题描述

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

问题分析

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

相关内容

热门资讯

政策激励“工具箱”为城市更新再... 本报记者 袁璐 1月1日,针对城市更新实践中的堵点难点问题,北京发布并实施《北京市城市更新政策激励工...
每周股票复盘:顾地科技(002... 截至2025年12月31日收盘,顾地科技(002694)报收于3.76元,较上周的3.82元下跌1....
每周股票复盘:采纳股份(301... 截至2025年12月31日收盘,采纳股份(301122)报收于26.06元,较上周的27.55元下跌...
每周股票复盘:日上集团(002... 截至2025年12月31日收盘,日上集团(002593)报收于5.91元,较上周的6.33元下跌6....
每周股票复盘:莱美药业(300... 截至2025年12月31日收盘,莱美药业(300006)报收于5.14元,较上周的5.26元下跌2....
每周股票复盘:辉隆股份(002... 截至2025年12月31日收盘,辉隆股份(002556)报收于6.04元,较上周的6.13元下跌1....
每周股票复盘:盛天网络(300... 截至2025年12月31日收盘,盛天网络(300494)报收于12.18元,较上周的11.95元上涨...
每周股票复盘:北新建材(000... 截至2025年12月31日收盘,北新建材(000786)报收于24.97元,较上周的24.75元上涨...
每周股票复盘:贝斯特(3005... 截至2025年12月31日收盘,贝斯特(300580)报收于26.29元,较上周的24.66元上涨6...
每周股票复盘:郑州银行(002... 截至2025年12月31日收盘,郑州银行(002936)报收于1.93元,较上周的1.95元下跌1....