大话设计模型 Task03:工厂、制造、观察

news2024/11/23 3:37:17

目录

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

一、建造者模式

在这里插入图片描述

问题描述

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

问题分析

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/101678.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

左偏树原理详解

一 点睛 左偏树(leftist tree 或 leftist heap)也叫作左偏堆、左倾堆、左式堆,是计算机科学中的一种树,也是一种优先队列实现方式,属于可并堆,在信息学中十分常见,在统计、最值、模拟、贪心等类…

Win11安装WSL2和Nvidia驱动(2022-12-19)

文章目录前言系统环境WSL 1和WSL 2功能对比安装WSL2更新和升级包配置VSCode配置GPU加速安装Nvidia驱动安装Cuda Toolkit通过PyTorch安装CUDA Toolkit测试Nvcc参考链接前言 以前捣鼓过wsl,即Windows下的Linux子系统,但兼容性依然比不过原生的Linux系统&a…

【Linux】进程间通信之管道

目录🌈前言🌸1、IPC介绍🍢1.1、进程间通信的目的🍡1.2、背景和发展🍠1.3、进程间通信的分类🌷2、管道🍡2.1、概念🍢2.2、管道的原理🍣2.3、匿名管道🍤2.4、管…

DOM算法系列004-判断给定节点是否为body元素

UID: 20221218221939 aliases: tags: source: cssclass: created: 2022-12-18 如果我们要判定给定的一个节点是不是页面body与元素节点,该如何判断呢? 一般来说, 一个HTML页面内只有一个body元素 但是,如果我们非要在页面内写超过…

Spring boot 整合 redis

Spring boot 整合 redis一、Spring boot 整合redis1.1 启动redis1.2 redis desktop manager1.3 常用命令二、操作2.1 依赖包2.2 配置2.3 简单测试2.4 StringRedisTemplate一、Spring boot 整合redis 1.1 启动redis 命令行启动 redis-server redis-cli1.2 redis desktop mana…

基于electronbot作品bootLoader设计

文章目录 前言 一、芯片程序区规划和流程 1、flash区规划 2、两区运行流程 3、bootLoader代码体现 4、electronbot代码体现: 二、bootLoader代码设计 1.下载程序步骤 2.通讯协议格式 三、libusb开发及需要注意的事情 1、bootLoader复合设备 2、electronbot复合设备…

基础算法系列--[基本数据结构KMP]

文章目录前言链表单链表双链表栈和队列栈队列单调KMP前言 今天要搞的是基本的一些数据结构,当然咱们这个不是那么“正经”。当然今天也没啥代码,因为太简单了(其实我也想水一下~) 链表 单链表 单链表这个东西,应该…

Prometheus+Grafana

K8S prometheusK8S1.Prometheus(普罗米修斯)2.Prometheus可以做什么3.Prometheus的特点4.prometheus 相关组件二、prometheus与zabbix的区别zabbix架构区别三、prometheus架构分析1.TSDB2.时间序列数据库的特点3.prometheus 相关组件1.prometheus 核心组…

【计算机网络】实验五 网络层与链路层协议分析(PacketTracer)

一、实验目的 通过本实验,进一步熟悉PacketTracer的使用,学习路由器与交换机的基本配置,加深对网络层与链路层协议的理解。 二、实验内容: 4.1 路由器交换机的基本配置 打开下面的实验文件,按提示完成实验。 4.2…

直流微电网中潮流(Matlab代码实现)

目录 1 概述 1.1 直流电网中的潮流 1.2 创新点和相关工作 1.3 本文结构 2 数学/网络模型 2.1 主-从操作 2.2 孤岛运行 3 牛顿法 4 案例及Matlab代码实现 1 概述 潮流是一个非线性问题,需要用牛顿法求解具有恒定功率端子的直流微电网。本文提出了牛顿法在…

曙光来临!Nature终于发现了新冠特效药?或将彻底终结新冠时代!

百趣代谢组学文献分享:2022年即将过去,随着疫苗的全面接种和三年以来“动态清零”的坚持,我们在应对新冠病毒如潮水般的攻击中取得了阶段性成果。虽然大家陆陆续续投入到正常的工作生活中,但是我们都知道新冠并未被“打败”&#…

MySQL中这14个有用的小知识,快学起来吧

前言 我最近用MYSQL数据库挺多的,发现了一些非常有用的小玩意,今天拿出来分享到大家,希望对你会有所帮助。 1.group_concat 在我们平常的工作中,使用group by进行分组的场景,是非常多的。 比如想统计出用户表中&…

如何在产品开发中讨论概念设计?

每当你看到一辆在路上行驶的汽车、书桌上的笔记本电脑、工业包装生产线、医院设备、家用仪器和其他形式的概念设计创意产品会感到难以置信,这就是我们在产品开发中讨论概念设计的原因。 概念设计是一个尚未解决或到目前为止尚未令人满意的问题。这是一个深思熟虑的解…

研究区域制图 | 在 ArcGIS Pro中创建地图布局

研究区域制图 | 在 ArcGIS Pro中创建地图布局 数据准备 首先需要两个图层,一个是市区图层,一个是省行政区划图层,我这里以吉林省以及吉林省长春市为例 新建布局 选择横向A5即可 添加参考线 不知道你们知不知道这个功能,反正小…

kotlin协程笔记:Dispatchers

Kotlin 的 launch 会调用 startCoroutineCancellable(),接着又会调用 createCoroutineUnintercepted(),最终会调用编译器帮我们生成 SuspendLambda 实现类当中的 create() 方法。 public fun CoroutineScope.launch(context: CoroutineContext EmptyC…

【JVM】本地方法栈与堆与方法区

文章目录1. 本地方法栈2. 堆3. 方法区1. 本地方法栈 本地方法栈和虚拟机栈有点类似,均具有线程隔离的特点以及都能抛出StackOverflowError和OutOfMemoryError异常。 但是不同之处在于本地方法栈服务的对象是JVM执行的native方法,而虚拟机栈服务的是JVM…

[附源码]Nodejs计算机毕业设计教师职称评定系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置: Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分…

免费提供POSMV的GNSS数据解算服务,验潮仪丢失的一种补救

前两天有个网友问干活的区域附近是否有长期验潮站,因为他的临时验潮仪丢失了,随后问了一下搞水文的同事,他推了一个网址: http://publictide.nmdis.org.cn/tide?SiteGroup3&TideType0,中文名叫:潮汐潮…

C型利钠肽 ,101135-67-5

Bz-VGR-pNA, chromogenic substrate for trypsin and for bacterial trypsin-like proteases.Bz-VGR-pNA,胰蛋白酶和细菌胰蛋白酶样蛋白酶的显色底物。 编号: 127015中文名称: C型利钠肽 (TYR0)-C-PEPTIDE (DOG)英文名: (Tyr0)-C-Peptide (dog)CAS号: 101135-67-5单…

机房动环监控系统3大价值,第一个太惊艳了

在中小学、大学院校中,机房已经是不可缺少的部分,但由于管理缺陷、设备复杂等缘故,学校机房得不到安全保障。 因此,要实现学校机房监控系统,来对机房的运行情况实时监测,以此提高风险预防及设备运行环境质量…