目录
- 一、建造者模式
- 问题描述
- 问题分析
- 模式定义
- 代码实现
- 二、观察者模式
- 问题描述
- 问题分析
- 模式定义
- 代码实现
一、建造者模式
问题描述
我的要求是你用程序画一个小人,这在游戏程序里非常常见,现在简单一点,要求是小人要有头、身体、两手、两脚就可以了。
问题分析
这里建造小人的’过程’是稳定的,都需要头身手脚,而具体建造的’细节’是不同的,有胖有瘦有高有矮。如果你需要将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示的意图时,我们需要应用于一个设计模式,‘建造者模式(Builder)’,又叫生成器模式。
模式定义
建造者模式(Builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
它主要用于创建一些复杂的对象,这些对象内部子对象的建造顺序通常是稳定的,但每个子对象本身的构建通常面临着复杂的变化。
代码实现
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from matplotlib.patches import Ellipse
class PersonBuilder(object):
def __init__(self, ax, color):
self.ax = ax
self.color = color
def build_head(self):
pass
def build_body(self):
pass
def build_arm_left(self):
pass
def build_arm_right(self):
pass
def build_leg_left(self):
pass
def build_leg_right(self):
pass
class 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 = pb
def 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 = name
self.sub = sub
def update(self):
pass
class Subject(object):
subjectState = ""
def attach(self, observer: Observer):
pass
def detach(self, observer: Observer):
pass
def notify(self):
pass
class 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.__action
def set_action(self, action):
self.__action = action
subjectState = 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.__action
def set_action(self, action):
self.__action = action
subjectState = 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()