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.委员会设计

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

委员会设计的原因如下:

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

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

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

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

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

相关文章

redis高可用-集群部署

一:背景 前面我们实现了redis的主从同步和哨兵模式,解决了单机redis的故障转移和流量分担,但是不管是主从或者哨兵模式都是一个主服务对应一个或者多个从服务,并且主服务和从服务的数据是一样的,这样就实现不了redis大…

远程桌面总是连接不上,mstsc远程总是连接不上解决方法

远程桌面连接在日常生活和工作中扮演着至关重要的角色,它允许用户在不同地点和设备之间无缝协作。然而,有时用户可能会遇到MSTSC(Microsoft远程桌面连接)总是连接不上的问题,这可能是由于多种原因造成的。本文将针对这…

C malloc经典面试题解答与分析

本篇博客介绍关于C malloc经典的错误代码写法以及解决方法。 题目1 错误的代码&#xff1a; #include <iostream>void test01(char* p) {p (char*)malloc(10); }int main1() {char* p NULL;test01(&p);const char* str "hello";strcpy(p, str);print…

Linux 线程的同步与互斥

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;Linux初窥门径⏪   &#x1f69a;代码仓库:Linux代码练习&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Linux知识   &#x1f51d; 前言 1.资源共享问题 2.进程线程间的互斥…

C语言程序设计-7 数组

在程序设计中&#xff0c;为了处理方便&#xff0c;把具有相同类型的若干变量按有序的形式组织起来。这些按序排列的同类数据元素的集合称为数组。在&#xff23;语言中&#xff0c;数组属于构造数据类型。一个数 组可以分解为多个数组元素&#xff0c;这些数组元素可以是基本数…

晶体振荡电路中的负性阻抗是什么?-晶发电子

在理想的振荡电路中&#xff0c;为了保持振荡的稳定性和强度&#xff0c;需要一种机制来补偿晶振振动过程中的能量损耗。在实际应用中&#xff0c;这种能量损耗是不可避免的&#xff0c;它可能导致振荡逐渐衰减直至停止。为了解决这个问题&#xff0c;振荡电路设计者采用了一种…

【MySQL数据库编程 存储过程触发器 示例】

1&#xff0e;利用不同的分支语句实现输入学生成绩&#xff0c;输出成绩等级。&#xff08;对于百分制成绩&#xff0c;60分以下为不及格&#xff0c;大于60分且小于或等于70分为及格&#xff0c;大于70分且小于或等于80分为中&#xff0c;大于80分且小于或等于90分为良&#x…

公司怎么管理文档外发泄密?强化企业文档安全用迅软加密软件就行了!

一、文档加密软件原理 迅软DSE加密软件对各类需要加密的文件&#xff08;如&#xff1a;技术资料、商业数据、红头文件、会议纪要、机要文件、图纸、财务报表等&#xff09;进行加密。 使用加密算法对文件自动加密&#xff0c;只有拥有正确的解密密钥或密码的人才能打开文件&…

语言模型测试系列【10】

一个巧合&#xff0c;又测到了新的区别&#xff0c;以下是关于python代码生成的测试效果。 语言模型 文心一言讯飞星火通义千问2.5豆包360智脑百小应腾讯元宝KimiC知道商量智谱清言 这次的测试问题来源于**智谱AI开放平台**的介绍&#xff0c;正好有个python生成的效果说明…

使用新语法连接Qt 5中重载的信号和槽

在使用Qt 5中的新信号和槽连接语法&#xff08;使用成员函数指针&#xff09;时&#xff0c;我遇到了一些问题。根据新的信号槽语法的描述&#xff0c;我尝试将以下代码&#xff1a; QObject::connect(spinBox, SIGNAL(valueChanged(int)),slider, SLOT(setValue(int)));改为&…

韩顺平0基础学java——第28天

p569-591 坦克大战&#xff01;&#xff08;绘图监听事件线程文件处理&#xff09; 绘图 绘图原理 Component类提供了两个和绘图相关最重要的方法: 1. paint(Graphics g)绘制组件的外观 2. repaint()刷新组件的外观。 当组件第一次在屏幕显示的时候,程序会自动的调用paint()…

智能网联汽车实训教学“好帮手”——渡众机器人自动驾驶履带车

智能网联汽车实训教学“好帮手”——渡众机器人自动驾驶履带车 人工智能技术的兴起&#xff0c;为传统汽车行业注入了强有力的变革基因&#xff0c;以AI技术为驱动的无人驾驶成为汽车产业的未来&#xff0c;同样也面临诸多机遇和挑战。 一方面智能网联汽车的发展&#xff0c;为…

GD32学习

参考视频13.立创开发板GD32教程&#xff1a;串口配置_哔哩哔哩_bilibili 固件库跟用户手册基本上差不多&#xff0c;只不过用用户手册编写程序的话会更加的底层&#xff0c;固件库的话就是把一些函数封装起来&#xff0c;用的时候拿过来即可&#xff0c;目前我还没有找到固件库…

【数据库备份完整版】物理备份、逻辑备份,mysqldump、mysqlbinlog的备份方法

【数据库备份完整版】物理备份、逻辑备份&#xff0c;mysqldump、mysqlbinlog的备份方法 一、物理备份二、逻辑备份1.mysqldump和binlog备份的方式&#xff1a;2.mysqldump完整备份与恢复数据2.1 mysqldump概念2.2 mysqldump备份2.3 数据恢复2.4 **使用 Cron 自动执行备份**2.5…

SpringBoot使用Redisson实现可重入分布式锁

pom.xml <dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.15.1</version></dependency>application.yml spring:redis:host: localhostport: 6379模拟获取锁 …

linux下编译安装和使用cURL库(含有openssl)

cURL是一个利用URL语法指定各种协议(如HTTP、HTTPS、FTP等)进行数据传输的工具,它以客户端的身份,允许用户通过命令行与服务器交互。cURL库(libcurl)是cURL的编程接口(API),提供了一套丰富的函数,供开发者在自己的应用程序中实现网络传输功能 cURL库是网络编程中不可…

搭建一个简单的xxljob

数据库表结构&#xff1a; YyJobInfo&#xff1a; public class YyJobInfo {//定时任务idprivate int id;//该定时任务所属的执行器的idprivate int jobGroup;//定时任务描述private String jobDesc;//定时任务添加的时间private Date addTime;//定时任务的更新时间private D…

服务器权限管理

我们linux服务器上有严格的权限等级&#xff0c;如果权限过高导致误操作会增加服务器的风险。所以对于了解linux系统中的各种权限及要给用户&#xff0c;服务等分配合理的权限十分重要。&#xff08;权限越大&#xff0c;责任越大&#xff09; 1.基本权限 U--user用户,G-group…

智谱API调用

一、智谱API 文心一言api 千帆大模型平台 申请和使用 智谱AI开放平台 登录智谱AI开放平台&#xff0c;点击右上角的开发者工作台&#xff0c;然后查看自己的API glm-4 接口 conda create -n zhipuai python3.10 -y 二、如何使用 这边的介绍是根据官方文档的接口文档来进行介绍…

深度学习之绘图基础

文章目录 1.实验目的2. 需求3.代码结果图片 1.实验目的 熟练绘制各种图像&#xff0c;为深度学习打基础 2. 需求 给定一个函数&#xff0c;需要你画出原图像以及这个函数在某点切线图像 3.代码 # File: python绘制函数图像以及倒数图像.py # Author: chen_song # Time: 20…