当前位置: 首页 > news >正文

Python 设计模式(第2版) -- 第四部分(其他设计模式)

Python 设计模式(第2版)

最后介绍下其他设计模式。

模型—视图—控制器(MVC)-- 复合模式

根据 GoF 的定义,“复合模式将两个或更多模式组合成解决常见或普遍性问题的解决方案”。复合模式不是同时使用的一组模式,而是一个问题的通用解决方案。

MVC 不仅是一种实现用户界面的软件模式,同时也是一种易于修改和维护的架构。通常来说,MVC 模式将应用程序分为3个基本部分:模型、视图和控制器。

MVC 模式的工作机制为:模型提供数据和业务逻辑(如何存储和查询信息),视图负责数据的展示(如何呈现),而控制器是两者之间的粘合剂,根据用户要求的呈现方式来协调模型和视图。

MVC 设计模式使用以下术语——模型、视图、控制器和客户端。

  • 模型:声明一个存储和操作数据的类。
  • 视图:声明一个类来构建用户界面和显示数据。
  • 控制器:声明一个连接模型和视图的类。
  • 客户端:声明一个类,根据某些操作来获得某些结果。

MVC 模式经常用于以下情况。

  • 当需要更改展示方式而不更改业务逻辑时。
  • 多个控制器可用于使用多个视图来更改用户界面上的展示。
  • 再次重申,当模型改变时,视图无需改动,因为它们是相互独立的。

简而言之,MVC 模式的主要意图如下。

  • 将数据和数据的展示隔离开来。
  • 使类的维护和实现更加简单。
  • 灵活地改变数据的存储和显示方式。两者都是独立的,因此可以灵活修改。

为了实现了一个 MVC 设计模式,假设我们想要开发一个应用程序,告诉用户云公司所提供的营销服务,包括电子邮件、短信和语音设施。

首先要开发 model 类(模型),定义产品提供的服务,即电子邮件、短信和语音。然后,来定义 view 类(视图),它提供了将信息反馈给客户端的方法。这些方法是 list_services() 和 list_ pricing()。接下来,开始定义 Controller 类,这个类定义了两个方法,即 get_services() 和 get_pricing()。这两个方法都是用来查询模型并获取数据的,然后将数据馈送到视图,从而展示给用户。Client 类将实例化控制器,然后控制器对象就会根据客户端的请求来调用适当的方法。

class Model(object):services = {"email": {"number": 1000, "price": 2,},"sms": {"number": 1000, "price": 10,},"voice": {"number": 1000, "price": 15,},}class View(object):def list_services(self, services):for svc in services:print(svc, " ")def list_pricing(self, services):for svc in services:print("For", Model.services[svc]["number"], svc, "message you pay $", Model.services[svc]["price"],)class Controller(object):def __init__(self):self.model = Model()self.view = View()def get_services(self):services = self.model.services.keys()return self.view.list_services(services)def get_pricing(self):services = self.model.services.keys()return self.view.list_pricing(services)class Client(object):controller = Controller()print("Services Provided:")controller.get_services()print("Pricing for Services:")controller.get_pricing()Client()

以下是MVC模式的优点。

  • 使用 MVC,开发人员可以将软件应用程序分为 3 个主要部分:模型、视图和控制器。这有助于提高可维护性,强制松耦合,并降低复杂性。
  • MVC 允许对前端进行独立更改,而对后端逻辑无需任何修改或只需进行很少的更改,因此开发工作仍可以独立运行。
  • 类似地,可以更改模型或业务逻辑,而无需对视图进行任何更改。
  • 此外,可以更改控制器,而不会对视图或模型造成任何影响。
  • MVC 还有助于招聘具有特定能力的人员,例如平台工程师和UI工程师,他们可以在自己的专业领域独立工作。

状态设计模式 – 状态设计模式

状态模式也属于行为模式的范畴,在此模式中,一个对象可以基于其内部状态封装多个行为。状态模式也可以看作是在运行时改变对象行为的一种方式。

状态设计模式在 3 个主要参与者的协助下工作。

  • State:这被认为是封装对象行为的接口。这个行为与对象的状态相关联。
  • ConcreteState:这是实现 State 接口的子类。ConcreteState 实现与对象的特定状态相关联的实际行为。
  • Context:这定义了客户感兴趣的接口。Context 还维护一个 ConcreteState 子类的实例,该子类在内部定义了对象的特定状态的实现。

考察一个状态设计模式的真实用例。例如,以一个计算机系统(台式机/笔记本电脑)为例:它可以有多个状态,如开机、关机、挂起或休眠。想利用状态设计模式来表述这些状态,看看如何处理。

首先,不妨从 ComputerState 接口开始入手:state 应定义两个属性,它们是 name 和 allowed。属性 name 表示对象的状态,而属性 allowed 是定义允许进入的状态的对象的列表;state 必须定义一个 switch() 方法,由它来实际改变对象(在这种情况下是计算机)的状态。

下面,来考察实现了 State 接口的 ConcreteState。On:这将打开计算机。这时候允许的状态是 Off、Suspend 和 Hibernate。Off:这将关闭计算机。这时候允许的状态只有 On。Hibernate:该状态将计算机置于休眠模式。当计算机处于这种状态时,只能执行打开操作。Suspend:该状态将使计算机挂起,一旦计算机挂起,就可以执行打开操作。

现在,来考察 context 类(Computer)。上下文需要做两个主要的事情:__init__():该方法定义了计算机的基本状态。change():该方法将更改对象的状态,但是行为的实际更改是由 ConcreteState 类实现(on、off、suspend 和 hibernate)的。

class ComputerState(object):name = "state"allowed = []def switch(self, state):if state.name in self.allowed:print('Current:', self, ' => switched to new state', state.name)self. __class__ = stateelse:print('Current:', self, ' => switching to', state.name, 'not possible.')def __str__(self):return self.nameclass Off(ComputerState):name = "off"allowed = ['on']class On(ComputerState):name = "on"allowed = ['off', 'suspend', 'hibernate']class Suspend(ComputerState):name = "suspend"allowed = ['on']class Hibernate(ComputerState):name = "hibernate"allowed = ['on']class Computer(object):def __init__(self, model='HP'):self.model = modelself.state = Off()def change(self, state):self.state.switch(state)if __name__ == "__main__":comp = Computer()# Switch oncomp.change(On)# Switch offcomp.change(Off)# Switch on againcomp.change(On)# Suspendcomp.change(Suspend)# Try to hibernate - cannot!comp.change(Hibernate)# switch on backcomp.change(On)# Finally offcomp.change(Off)

下面是状态设计模式的优点。

  • 在状态设计模式中,对象的行为是其状态的函数结果,并且行为在运行时根据状态而改变。这消除了对 if/else 或 switch/case 条件逻辑的依赖。例如,在电视远程遥控的场景中,我们还可以通过简单地写一个类和方法来实现相应的行为,但是该类和方法将用到参数,并使用 if/else 语句块来执行具体操作(打开/关闭电视)。
  • 使用状态模式,实现多态行为的好处是显而易见的,并且更易于添加状态来支持额外的行为。
  • 状态设计模式还提高了聚合性,因为特定于状态的行为被聚合到 ConcreteState 类中,并且放置在代码中的同一个地方。
  • 使用状态设计模式,通过只添加一个 ConcreteState 类来添加行为是非常容易的。因此,状态模式不仅改善了扩展应用程序行为时的灵活性,而且全面提高了代码的可维护性。

状态模式的不足:

  • 类爆炸:由于每个状态都需要在 ConcreteState 的帮助下定义,因此我们可能导致创建了太多功能较为单一的类。我们不妨考虑有限状态机的情况——如果有许多状态,但每个状态与另一个状态没有太大不同,我们仍然需要将它们写成单独的 ConcreteState 类。这既增加了代码量,又使得状态机的结构更加难以审查。
  • 随着每个新行为的引入(即使添加行为只是添加一个 ConcreteState),Context 类都需要进行相应的更新以处理每个行为。这使得上下文行为更容易受到每个新的行为的影响。

反模式

反模式是处理重复出现问题的某些解决方案的后果。

反模式可以分为两大类。1.软件开发反模式。2.软件架构反模式。

软件开发反模式

下面,将列举软件开发中的几种反模式。

1.意大利面条式代码

以特殊的方式开发结构,软件控制流会变得错综复杂。

意大利面条式代码的典型成因包括:

  • 对面向对象编程和分析的无知;
  • 没有考虑产品的架构或设计;
  • 快餐式思维。

当遭遇意大利面条式代码时,就会面临下列问题:

  • 结构的重用性将会降到最低;
  • 维护工作量过高;
  • 进行修改时,扩展性和灵活性会降低。

2.金锤

由于某个解决方案(技术、设计或模块)在多个项目中效果不错,所以就把它推广到更多的地方。一把锤子搞定所有的钉子(解决所有问题)。

之所以出现金锤,典型的原因有如下几个:

  • 来自不了解具体问题的高层(架构师或技术领袖)的建议;
  • 虽然某解决方案在过去多次验证有效,但当前项目却具有不同的背景和要求;
  • 公司已经被这种技术“绑架”了,因为他们已经在它上面投资了大量资金来培训员工,或员工们对这种技术情有独钟,因为已经用顺手了。

3.熔岩流

这个反模式与软件应用程序中的死代码或一段用不到的代码有关,随着时间的流逝,这段代码会一直留在软件中并固化其位置,就像熔岩变成硬岩一样。

熔岩流的成因包括以下几个:

  • 在产品中有大量的试错代码;
  • 由一个人单独编写的代码,未经审查,就在没有任何培训的情况下移交给了其他开发团队;
  • 软件架构或设计的初始思想是通过代码库实现的,但没有人能理解它。

熔岩流的症状如下:

  • 开发的测试工作(如果完成的话)具有很低的代码覆盖率;
  • 代码中含有莫名奇妙的注释;
  • 过时的接口,或开发人员需要围绕既有代码展开工作;

4.复制粘贴或剪切粘贴式编程

这是最常见的反模式之一。有些开发人员为了提高开发进度,经常会原封不动地复制这些片段,并用于自己的应用程序中。

导致复制粘贴或剪切粘贴式编程的原因如下:

  • 新手开发者不习惯编写代码或不知道如何开发代码;
  • 快速修复bug或“急就章”式的开发;
  • 代码重复,无法满足跨模块标准化以及代码结构化的要求;
  • 缺乏长远打算或深谋远虑。

剪切粘贴或复制粘贴式编程的后果包括:

  • 多个软件应用程序存在同种类型的问题;
  • 维护成本会更高,同时bug的生命周期也会变得更长;
  • 较少的模块化代码库,相同的代码会散落于多处;
  • 继承问题。

软件架构反模式

1.重新发明轮子

重新审视相同的问题并为它重新设计解决方案并没有什么意义,这基本上就是重新发明轮子。

导致重新发明轮子的原因如下:

  • 缺乏中央文档或存储库来讲解架构级问题和存放已实现的解决方案;
  • 社区或公司内的技术领袖之间缺乏沟通;
  • 组织中遵循的流程是从头开始构建的,通常情况下,这样的流程是不成熟的,并且流程的实现通常是不严谨的,并且很难坚持。

这种反模式的后果如下所示:

  • 解决一个标准问题的解决方案太多,其中许多解决方案考虑得并不周全;
  • 会耗费工程团队更多的时间和资源,导致预算超标,上市时间延后;
  • 封闭的系统架构(仅适用于一种产品的架构)、重复劳动和糟糕的风险管理。

2.供应商套牢

正如这种反模式的名称所示,产品公司往往依赖于供应商提供的某些技术。这些技术对于他们的系统来说如此密不可分,以至于系统很难摆脱这些技术。

以下是导致供应商锁定的原因:

  • 熟悉供应商公司的权威人士以及技术采购的可能折扣;
  • 基于营销和销售业务而不是技术评估选择的技术;
  • 在当前项目中使用经过验证的技术(验证表明,使用此技术的投资回报率非常高),即使它不适合当前项目的需要或要求;
  • 技术人员/开发人员已经接受过相关技术的培训。

供应商锁定的后果如下所示:

  • 公司产品的发布周期和维护周期直接取决于供应商的发布时间;
  • 该产品是围绕该技术而不是根据客户的要求开发的;
  • 产品上市时间不可靠,不能满足客户的期望。

3.委员会设计

有时,根据组织中的流程,一群人会坐在一起来设计特定的系统,所得到的软件架构通常是复杂的或不合格的。因为这涉及太多的思维过程,并且这些设计思想可能是由没有相应的技能或相应产品设计经验的技术专家所提出的。

委员会设计的原因如下:

  • 根据组织的流程,产品的架构或设计是由众多的利益相关者批准的;
  • 没有指定单独的联系人或负责设计的架构师;
  • 由营销或技术专家确定设计优先级,而不是由客户反馈来确定。

与该模式有关的症状如下所示:

  • 开发人员和架构师之间的观点冲突,即使在设计完成后依旧如此;
  • 过于复杂的设计,很难记录;
  • 规格或设计的任何改动都需要经过多次审查,导致实现延迟。

相关文章:

Python 设计模式(第2版) -- 第四部分(其他设计模式)

Python 设计模式(第2版) 最后介绍下其他设计模式。 模型—视图—控制器(MVC)-- 复合模式 根据 GoF 的定义,“复合模式将两个或更多模式组合成解决常见或普遍性问题的解决方案”。复合模式不是同时使用的一组模式,而是一个问题的…...

gitlab升级16.11.3-ee

背景 这是事后一段时间补充记录的博客。 升级目的:修补漏洞CVE-2024-4835 未经认证的威胁攻击者能够利用该漏洞在跨站脚本 (XSS) 攻击中,轻松接管受害者账户。 gitlab版本为14.6.2-ee升级至16.11.3-ee 思路 翻阅文档找升级方法及升级版本路径。使用…...

剑指offer 算法题(搜索二维矩阵)

剑指offer 第二题 去力扣里测试算法 思路一&#xff1a; 直接暴力遍历二维数组。 class Solution { public:bool searchMatrix(vector<vector<int>>& matrix, int target) {for (unsigned int i{ 0 }; i < matrix.size(); i){for (unsigned int j{ 0 };…...

SaaS平台数据对接为什么要选择API对接?

SaaS平台数据对接是指将一个或多个SaaS平台中的数据集成到其他应用或平台中的过程。在当前的数字化时代&#xff0c;企业越来越倾向于使用SaaS平台来管理他们的业务和数据。然而&#xff0c;这些数据通常散布在不同的SaaS平台中&#xff0c;这对于企业数据的整合和分析来说可能…...

力扣136. 只出现一次的数字

Problem: 136. 只出现一次的数字 文章目录 题目描述思路复杂度Code 题目描述 思路 由于题目要求使用线性时间复杂度和常量级的空间复杂度&#xff0c;再加上找重复元素这个特性&#xff0c;我们可以想到使用位运算来求解&#xff1a; 1.任何数与其本身异或得0&#xff0c;任何…...

重学java 74.Lombok的使用

少点心气&#xff0c;多点干劲 —— 24.6.18 一、lombok的安装使用 1.作用: 简化javabean开发 2.使用: a.下插件 ->如果是idea2022不用下载了,自带 b.导lombok的jar包 安装教程&#xff1a; http://t.csdnimg.cn/wq9MM c.修改设置 二、lombok的介绍 Lombok通过增加一…...

数据结构6---树

一、定义 树(Tree)是n(n>0)个结点的有限集。当n0时成为空树,在任意一棵非空树中: 1、有且仅有一个特定的称为根(Root)的结点; 2、当n>1时,其余结点可分为m(m>日)个互不相交的有限集T1、T2、...、 Tm&#xff0c;其中每一个集合本身又是一棵树&#xff0c;并且称为根的…...

一键制作,打造高质量的数字刊物

随着数字化时代的到来&#xff0c;数字刊物已经成为信息传播的重要载体。它以便捷、环保、互动性强等特点&#xff0c;受到了越来越多人的青睐。然而&#xff0c;如何快速、高效地制作出高质量的数字刊物&#xff0c;成为许多创作者面临的难题。今天&#xff0c;教大家一个制作…...

Java面试题:对比继承Thread类和实现Runnable接口两种创建线程的方法,以及它们的优缺点

Java 中创建线程有两种主要的方法&#xff1a;继承 Thread 类和实现 Runnable 接口。下面我将分别介绍这两种方法&#xff0c;并对比它们的优缺点。 继承 Thread 类 方法&#xff1a; 创建一个继承自 Thread 的子类。重写 Thread 类的 run 方法。创建子类的实例并调用 start…...

编译原理-各章典型题型+思路求解

第2章文法和语言习题 基础知识&#xff1a; 思路&#xff1a; 基础知识&#xff1a; 思路&#xff1a; 基础知识&#xff1a; 编译原理之 短语&直接短语&句柄 定义与区分_编译原理短语,直接短语,句柄-CSDN博客 思路&#xff1a; 题目&#xff1a; 基础解释&#xff1a…...

【绝对有用】C++ vector排序

在 C 中&#xff0c;有多种方法可以对向量&#xff08;即 std::vector&#xff09;进行排序。最常用的方法是使用标准库中的 std::sort 函数。以下是一些例子&#xff1a; 使用 std::sort 函数 std::sort 函数是标准库 <algorithm> 中的一个函数&#xff0c;可以对向量…...

linux——VScode安装

方法一&#xff1a;使用snap一键安装 Snap Store 是 Ubuntu、Debian、Fedora 和其他几个 Linux 发行版中的一个应用商店&#xff0c;提供了数千个应用程序和工具的安装。Snap Store 使用 Snap 包格式&#xff0c;这是一种通用的 Linux 软件包格式&#xff0c;使得在不同的 Lin…...

X-LoRA:高效微调 LoRA 系列,实现不同领域知识专家混合模型

&#x1f4dc; 文献卡 X-LoRA: Mixture of Low-Rank Adapter Experts, a Flexible Framework for Large Language Models with Applications in Protein Mechanics and Molecular Design作者: Eric L. Buehler; Markus J. BuehlerDOI: 10.48550/arXiv.2402.07148摘要:We report…...

基于卷积神经网络的目标检测

卷积神经网络基础知识 1.什么是filter 通常一个6x6的灰度图像&#xff0c;构造一个3*3的矩阵&#xff0c;在卷积神经网络中称之为filter,对&#xff16;x6的图像进行卷积运算。 2.什么是padding 假设输出图像大小为nn与过滤器大小为ff&#xff0c;输出图像大小则为(n−f1)∗(…...

Mysqld数据库管理

一.Mysqld数据库类型 常用的数据类型 int 整型 无符号[0-4294967296&#xff08;2的32次方&#xff09;-1]&#xff0c;有符号[-2147483648&#xff08;2的31次方&#xff09;-2147483647]float单精度浮点 4字节32位double双精度浮点 8字节64位char固定长度的字符类型…...

Wifi通信协议:WEP,WPA,WPA2,WPA3,WPS

前言 无线安全性是保护互联网安全的重要因素。连接到安全性低的无线网络可能会带来安全风险&#xff0c;包括数据泄露、账号被盗以及恶意软件的安装。因此&#xff0c;利用合适的Wi-Fi安全措施是非常重要的&#xff0c;了解WEP、WPA、WPA2和WPA3等各种无线加密标准的区别也是至…...

开源【汇总】

开源【汇总】 前言版权推荐开源【汇总】最后 前言 先占个位 2024-6-21 21:29:33 以下内容源自《【创作模板】》 仅供学习交流使用 版权 禁止其他平台发布时删除以下此话 本文首次发布于CSDN平台 作者是CSDN日星月云 博客主页是https://jsss-1.blog.csdn.net 禁止其他平台发…...

英文字母表

目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 namespace 英文字母表 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){foreach (var item in panel1.Controls){if (item ! null)…...

Redis缓存穿透

缓存穿透&#xff1a; 查询一个不存在的数据&#xff0c;mysql查询不到数据也不会直接写入缓存&#xff0c;就会导致每次请求都查数据库。 方法一&#xff1a; 方法二&#xff1a; 布隆过滤器&#xff1a; 简单来说就是一个二进制数组&#xff0c;用0和1来判断数组中是否存在…...

SHELL脚本学习(十一)正则表达式

一、锚点字符 1.1 锚点行首 脱字符(^)指出行首位置 $ cat < file1 test line1 test line2 test line3 line4 test#打印所有包括文本 test的行 $ sed -n /test/p file1 test line1 test line2 test line3 line4 test#打印所有以test为首的行 $ sed -n /^test/p file1 test…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机&#xff1a;Ubuntu 20.04.6 LTSHost&#xff1a;ARM32位交叉编译器&#xff1a;arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天&#xff0c;深度学习与大模型技术已成为推动行业变革的核心驱动力&#xff0c;而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心&#xff0c;系统性地呈现了两部深度技术著作的精华&#xff1a;…...