设计模式及创建型模式-python版

1 架构模式与设计模式

架构模式搞层次的设计模式, 描述系统整体结构和组织方式,设计模式是针对某个问题的解决方案,是一种解决问题的思路。

2 设计模式的分类

2.1 创建型模式

单例模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式

2.2 结构型模式

适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式

2.3 行为型模式

策略模式,模板方法模式,观察者模式,迭代子模式,责任链模式,命令模式,备忘录模式,状态模式,访问者模式,中介者模式,解释器模式

3 设计模式的六大原则

  • 单一职责原则:一个类只负责一个功能领域中的相应职责
  • 开闭原则:对扩展开放,对修改关闭
  • 里氏替换原则:任何基类可以出现的地方,子类一定可以出现
  • 依赖倒转原则:针对接口编程,依赖于抽象而不依赖于具体
  • 接口隔离原则:使用多个隔离的接口,比使用单个接口要好
  • 迪米特法则:一个实体应当尽量少的与其他实体发生相互作用
  • 合成复用原则:尽量使用合成/聚合的方式,而不是使用继承

4 设计模式举例

4.1 单例模式

单例模式(Singleton)用在软件运行过程中仅需要一个实例的场景,如软件的主界面, 系统全局统一管理(win 下的task manager)等。

  1. 举例
    用单例模式来模拟计算机的总线地址, 处理器中的多个线程可以调用总线地址(单例)来发送消息。
import threading
import time
class Singleton(object):def __new__(cls, *args, **kw):if not hasattr(cls, '_instance'):orig = super(Singleton, cls)cls._instance = orig.__new__(cls, *args, **kw)return cls._instanceclass Bus(Singleton):lock = threading.RLock()def sendData(self, data):self.lock.acquire()time.sleep(3)print("Sending Signal Data...", data)self.lock.release()class VisitEntity(threading.Thread):my_bus = ""name = ""def getName(self):return self.namedef setName(self, name):self.name = namedef run(self):self.my_bus = Bus()self.my_bus.sendData(self.name)if __name__ == "__main__":for i in range(3):print("Entity %d begin to run..." % i)my_entity = VisitEntity()my_entity.setName("Entity_"+str(i))my_entity.start()

上述代码中 Bus 继承了Singleton, 每创建一个Bus 对象, 实际上返回的都是同一个对象。

  1. 优缺点
    单例模式要求在全局只有一个实例, 可以节省内存空间;全局只有一个接入点, 可以更高的进行数据控制, 避免过多的占用;单例可以常驻内存, 减少系统开销。
    单例模式的扩展是比较困难的;赋予单例太多的职责, 某种程度上违反单一职责原则;单例模式在某种情况下会导致资源瓶颈

4.2 工厂方法模式

工厂方法模式(Factory Method Pattern)是在简单工厂模式(定义一个工厂类,根据传入的参数决定创建哪一种产品类的实例)基础上的递进。它通过定义一个创建对象的接口, 由子类决定实例化哪一个类。工厂方法模式使一个类的实例化延迟到其子类, 简言之, 就是父类提供一个接口, 子类来决定实例化哪个具体的类。

类图

  1. 举例
from abc import ABC, abstractmethod# 定义Shape接口
class Shape(ABC):@abstractmethoddef draw(self):pass# 实现Circle类
class Circle(Shape):def draw(self):print("Drawing a Circle")# 实现Square类
class Square(Shape):def draw(self):print("Drawing a Square")# 定义ShapeFactory接口
class ShapeFactory(ABC):@abstractmethoddef create_shape(self):pass# 实现CircleFactory类
class CircleFactory(ShapeFactory):def create_shape(self):return Circle()# 实现SquareFactory类
class SquareFactory(ShapeFactory):def create_shape(self):return Square()# 使用示例
if __name__ == "__main__":circle_factory = CircleFactory()shape1 = circle_factory.create_shape()shape1.draw()  # 输出: Drawing a Circlesquare_factory = SquareFactory()shape2 = square_factory.create_shape()shape2.draw()  # 输出: Drawing a Square

上述例子定义了形状类产品的接口及其两个具体的实现类, 工厂接口及其两个具体的实现, 每个工厂负责生产一种形状产品。

  1. 优缺点
    解耦:将对象的创建过程与使用过程分离,降低了代码的耦合度;
    灵活性:通过子类来决定具体实例化哪个类,增加了代码的灵活性;
    扩展性:增加新的产品类时,只需添加相应的工厂类即可,不需要修改现有代码。
    类的数量增加:每增加一个产品类,都需要增加一个相应的工厂类,导致类的数量增多;
    代码复杂度提高:增加了系统的复杂性,理解起来可能会有些困难。

4.3 抽象工厂模式

在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。

抽象工厂模式(Abstract Factory)与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。

在这里插入图片描述

  1. 举例
from abc import ABCMeta, abstractmethodclass Refrigerator(metaclass=ABCMeta):@abstractmethoddef use(self):passclass Refrigerator1(Refrigerator):def use(self):print("Haier refrigerator")class Refrigerator2(Refrigerator):def use(self):print("Meidi refrigerator")class Airconditioner(metaclass=ABCMeta):@abstractmethoddef go(self):passclass Airconditioner1(Airconditioner):def go(self):print("Haier Airconditioner")class Airconditioner2(Airconditioner):def go(self):print("Meidi Airconditioner")class Factory(metaclass=ABCMeta):@abstractmethoddef create_refrigerator(self):pass@abstractmethoddef create_airconditioner(self):passclass Factory1(Factory):def create_refrigerator(self):return Refrigerator1()def create_airconditioner(self):return Airconditioner1()class Factory2(Factory):def create_refrigerator(self):return Refrigerator2()def create_airconditioner(self):return Airconditioner2()if __name__ == '__main__':f = Factory1()r1 = f.create_refrigerator()r1.use()r2 = f.create_airconditioner()r2.go()f = Factory2()r1 = f.create_refrigerator()r1.use()r2 = f.create_airconditioner()r2.go()

上述例子定义了两个系列的产品:冰箱和空调, 每种产品又要区分不同的品牌。 定义了两个工厂实现类,分别负责生产不同品牌的产品。

  1. 优缺点
    优点
    “抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。”

“当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。”

“增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。”

缺点
“在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。”

“开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。”

4.4 建造者模式

建造者模式(Build)是把复杂对象的创建拆分成多个简单的步骤, 并将这些步骤封装在一个独立的建造者类中, 然后,我们可以使用一个指挥者类来控制建造者的调用顺序,以便在每个步骤完成后正确地构建复杂对象。

将对象的构建与其表示分离开来。这意味着我们可以使用相同的构建过程来创建不同的表示形式,而不必改变建造者的代码。

建造者模式是一种创建型设计模式,它允许您逐步构造复杂对象。与直接实例化复杂对象不同,建造者模式将对象的构造过程分解为一系列步骤,使您可以逐个处理这些步骤。

建造者模式的核心思想是将一个复杂对象的构造过程和它的表示分离开来,使得同样的构造过程可以创建不同的表示。通常情况下,一个建造者模式包括以下四个角色:

Product(产品):表示被建造的复杂对象,包含多个部件。
Builder(抽象建造者):定义构造过程的接口,包括创建各个部件的抽象方法。
ConcreteBuilder(具体建造者):实现 Builder 接口,构造和装配各个部件,同时提供一个返回产品的方法。
Director(指挥者):负责安排各个部件的构造顺序,告诉 Builder 需要创建哪些部件,以及如何组装它们。

  1. 举例
from abc import ABC, abstractmethod
class Product:def __init__(self):self.part_a = Noneself.part_b = Noneself.part_c = Noneclass Builder(ABC):def __init__(self):self.product = Product()@abstractmethoddef build_part_a(self):pass@abstractmethoddef build_part_b(self):pass@abstractmethoddef build_part_c(self):passclass ConcreteBuilder1(Builder):def build_part_a(self):self.product.part_a = "Part A1"def build_part_b(self):self.product.part_b = "Part B1"def build_part_c(self):self.product.part_c = "Part C1"class ConcreteBuilder2(Builder):def build_part_a(self):self.product.part_a = "Part A2"def build_part_b(self):self.product.part_b = "Part B2"def build_part_c(self):self.product.part_c = "Part C2"class Director:def __init__(self, builder):self.builder = builderdef construct(self):self.builder.build_part_a()self.builder.build_part_b()self.builder.build_part_c()return self.builder.product# Usage example
builder1 = ConcreteBuilder1()
director = Director(builder1)
product1 = director.construct()
print(product1.part_a)  # Output: Part A1
print(product1.part_b)  # Output: Part B1
print(product1.part_c)  # Output: Part C1builder2 = ConcreteBuilder2()
director = Director(builder2)
product2 = director.construct()
print(product2.part_a)  # Output: Part A2
print(product2.part_b)  # Output: Part B2
print(product2.part_c)  # Output: Part C2

上述代码定义了一个产品类, 分成三部分。 定义了一个抽象的建造者类, 定义了抽象的方法分别来建造产品的三部分, 而后实现了两个具体的构造者, 最后定一个Director 类来调用构造者。

  1. 优缺点
    优点:

将复杂对象的构造过程和表示分离。这使得客户端可以更加简单地创建对象,同时也使得代码更加灵活和易于维护。

可以使用相同的构造过程来创建不同的对象表示。因为建造者模式将构造过程和表示分离,所以您可以使用相同的构造过程来创建不同的对象表示。这样可以大大减少代码的重复,并且使得对象表示更加易于扩展。

支持逐步构建复杂对象。建造者模式允许您逐步构建复杂对象,因为您可以分解对象构造过程为一系列简单的步骤,并逐步完成每个步骤。这样可以使得构造过程更加可控,同时也有助于代码的维护和测试。

代码结构清晰。建造者模式的代码结构清晰,并且易于理解和扩展。因为建造者模式将构造过程分解为一系列步骤,并将其封装在不同的类中,所以可以更加清晰地组织代码。

缺点

建造者模式的实现较为复杂。由于建造者模式将对象的构造过程分解为多个步骤,所以需要创建多个类来实现建造者模式。这会增加代码量和复杂度,使得代码变得更难理解和维护。

建造者模式要求建造者类必须知道产品的内部结构。由于建造者类需要创建产品的各个部分并组装它们,所以必须了解产品的内部结构。这种紧密耦合的设计使得建造者模式的扩展性和灵活性变得较差。

建造者模式不适用于创建简单的对象。由于建造者模式将对象构造过程分解为多个步骤,所以如果要创建简单的对象,建造者模式会增加代码的复杂度,使得代码变得更加冗长和难以理解。

建造者模式可能会导致对象数量增加。由于建造者模式创建的对象是由多个部件组成的,所以可能会导致对象的数量增加,从而占用更多的内存空间。

4.5 原型模式

原型模式(Prototype)是一种创建型设计模式,它的主要思想是通过复制一个已经存在的对象来创建新的对象。这个已经存在的对象被称为原型对象,新的对象通过复制原型对象的属性和状态来创建。

在原型模式中,我们需要定义一个原型接口或抽象类,这个接口或抽象类中包含了一个 clone() 方法,用于复制原型对象。具体的原型对象实现这个接口或抽象类,并实现 clone() 方法。当需要创建新的对象时,我们可以通过调用原型对象的 clone() 方法来复制它,从而创建一个新的对象。

  1. 举例
import copy
from abc import ABC, abstractmethod# 定义原型类
class Prototype(ABC):@abstractmethoddef clone(self):pass# 定义具体原型类
class ConcretePrototype(Prototype):def __init__(self, name):self.name = namedef clone(self):return copy.deepcopy(self)def __str__(self):return self.name# 定义客户端类
class Client:def operation(self):# 创建原型对象prototype = ConcretePrototype("prototype")# 克隆原型对象clone1 = prototype.clone()clone2 = prototype.clone()# 输出克隆对象的名称print("Clone 1 name: " + str(clone1))print("Clone 2 name: " + str(clone2))# 测试代码
client = Client()
client.operation()
  1. 优缺点
    优点:

减少对象的创建时间和消耗的资源:原型模式通过复制已有对象来创建新对象,避免了重复创建对象的过程,因此可以大幅度减少对象的创建时间和消耗的资源。

可以避免因重复创建对象而造成的资源浪费:由于原型模式可以通过复制已有对象来创建新对象,因此避免了重复创建对象而造成的资源浪费。

动态地创建对象:原型模式可以动态地创建对象,因为它不需要预先知道要创建的对象的具体类型。

可以保持对象的一致性:由于原型对象与新对象拥有相同的属性和状态,因此可以保持对象的一致性。

可以提高系统性能:由于原型模式减少了对象的创建时间和消耗的资源,因此可以提高系统性能。

缺点:

原型对象的创建过程可能比较复杂:由于原型对象需要包含所有要复制的属性和状态,因此原型对象的创建过程可能比较复杂,尤其是当属性和状态是深层嵌套的时候。

使用场景比较有限:原型模式只有当需要创建的对象可以通过复制现有对象来创建时才适用,因此它的使用场景比较有限。

可能会增加代码的复杂度:由于原型模式需要维护原型对象和具体的原型实现类,因此可能会增加代码的复杂度。

克隆方法的实现可能比较困难:实现克隆方法需要考虑对象的深浅拷贝问题,如果对象的属性和状态比较复杂,那么实现克隆方法可能比较困难。

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

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

相关文章

JVM2-JVM组成、字节码文件、类的生命周期、类加载器

目录 Java虚拟机的组成 字节码文件 字节码文件打开方式 字节码文件的组成 基本信息 Magic魔数 主副版本号 常量池 字段 方法 属性 字节码常用工具 javap jclasslib插件 Arthas 类的生命周期 概述 加载阶段 连接阶段 验证 准备 解析 初始化阶段 类加载器…

linux 下一跳缓存,early demux(‌早期解复用)‌介绍

3.6版本以后的下一跳缓存 3.6版本移除了FIB查找前的路由缓存。这意味着每一个接收发送的skb现在都必须要进行FIB查找了。这样的好处是现在查找路由的代价变得稳定(consistent)了。3.6版本实际上是将FIB查找缓存到了下一跳(fib_nh)结构上,也就是下一跳缓存下一跳缓存…

ESP32无线WiFi芯片模组,设备物联网连接通信,产品智能化交互升级

在数字化浪潮的推动下,我们正步入一个万物互联的新时代。物联网(IoT)技术,作为连接物理世界与数字世界的桥梁,正逐渐渗透到我们生活的每一个角落。 乐鑫正通过其创新的无线WiFi芯片模组,为这些领域的发展提…

界面控件DevExpress中文教程:如何使用AI扩展Excel计算?

DevExpress WinForms拥有180组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜…

Elasticsearch的Restful风格API

前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 1、Restful及JSON格式 RESTFUL是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用 XML 格式定义或 JSON 格式定义。R…

STM32CubeMX CAN收发数据

目录 一、CAN总线 1. 差分信号 2. CAN收发器 3. CAN帧结构 4. CAN波特率设置 5. 标识符筛选 二、CubeMX配置 三、Keil代码 一、CAN总线 CAN(Controller Area Network,控制器局域网络)是一种用于车辆、工业自动化等领域的通信协议&…

springboot博客系统

基于springbootvue实现的博客系统 (源码L文ppt)4-031 4 系统设计 博客系统的整体结构设计主要分为两大部分:管理员和博主。他们的权限不同,于是操作功能也有所不同。整体结构设计如图4-2所示。 图4-2 系统结构图 4.3 数据库设…

Unity(2022.3.41LTS) - 角色控制器和3D刚体

目录 一. 角色控制 二. 3D刚体 一. 角色控制 名称:功能:坡度限制将碰撞器限制为仅爬升比指示值更陡峭(以度为单位)的斜坡。步长偏移只有当楼梯离地面比指示值更近时,角色才会爬上楼梯。此值不应大于 Character Contr…

《CounTR: Transformer-based Generalised Visual Counting》CVPR2023

摘要 本论文考虑了通用视觉对象计数问题,目标是开发一个计算模型,用于计算任意语义类别的对象数量,使用任意数量的“样本”(即可能为零样本或少样本计数)。作者提出了一个新颖的基于Transformer的架构,称为…

shell 学习笔记:变量、字符串、注释

目录 1. 变量 1.1 定义使用变量 1.2 变量命名规则 1.3 只读变量 1.4 删除变量 1.5 变量类型 1.5.1 字符串变量 1.5.2 整数变量 1.5.3 数组变量 1.5.3.1 整数索引数组 1.5.3.2 关联数组 1.4 环境变量 1.5 特殊变量 2. 字符串 2.1 单引号字符串 2.2 双引…

【32项目】基于stm32f103c8t6WIFI远程监控智慧农业大棚(含完整代码)

目录 前言 设计背景 设计原理 所需材料 JW01二氧化碳传感器介绍 YL-69土壤湿度传感器介绍 PCB及原理图 部分代码(完整代码见文章末尾) 前言 随着农业现代化的发展,智慧农业的概念越来越受到重视。智慧农业利用物联网、大数据、人工智…

计算机网络 数据链路层2

ALOHA:想发就发 CSMA 载波监听多路访问协议 CS:载波监听,在发送数据之前检测总线上是否有其他计算机在发送数据 1-坚持CSMA:主机想发送消息,需要监听信道; 信道空闲则直接传输信息; 信道忙碌则一直监听,直…

【JavaWeb】JDBCDruidTomcat入门使用

本章使用技术版本: Tomcatv10.1.25 关于javaweb相关的其他技术,比如tomcat和maven,在我的主页记录了笔记,ajax我用的是本地笔记以后再考虑上传,前端三板斧我用的菜鸟教程文档 JDBC 初识 JDBC概念 JDBC 就是使用Jav…

【深度学习 transformer】使用pytorch 训练transformer 模型,hugginface 来啦

Hugging Face是一个致力于开源自然语言处理(NLP)和机器学习项目的社区。它由几个关键组件组成: Transformers:这是一个基于PyTorch的库,提供了各种预训练的NLP模型,如BERT、GPT、RoBERTa、DistilBERT等。它…

SEO之网站结构优化(十四-内部链接及权重分配3)

初创企业搭建网站的朋友看1号文章;想学习云计算,怎么入门看2号文章谢谢支持: 1、我给不会敲代码又想搭建网站的人建议 2、“新手上云”能够为你开启探索云世界的第一步 博客:阿幸SEO~探索搜索排名之道 7、锚文字分布及变化 前面…

WebGIS与WebGL是什么,两者之间的关系?

WebGL和 WebGlS 都是 web 技术领域的重要内容,特别是这几年webgis开发领域,和webgl打交道是必然的,常见的WebGL开发的基础上,比如二维的Leaflet、三维的Cesium也都是热门。 WebGL是一种基于 HTML5 Canvas 元素的 JavaScriptAPI&a…

RLHF(带有人类反馈的强化学习)初探

我的目标是,在决策游戏上学习某人风格,可以让人对战“带有某人风格”的AI,比如你可以在这里对战“sky风格的AI”,这样的效果。 我最开始受到的启发来源于xbox的广告《爸爸的幽灵车》,已故人在游戏中留下的速度记录的固定轨迹。 …

IOS17.0安装巨魔:TrollRestore巨魔发布

👻 TrollRestore 17.0 巨魔发布 15.0 - 16.7 RC(20H18)和17.0。 官网:https://trollrestore.com/ 下载:https://pan.metanetdisk.com/IOS/%E5%B7%A8%E9%AD%94%E7%8E%A9%E5%AE%B6/TrollRestore.com 使用:ht…

【数字人】Facevid2vid:用于视频会议的一次性自由视图说话头合成

论文:https://arxiv.org/pdf/2011.15126 github:GitHub - zhanglonghao1992/One-Shot_Free-View_Neural_Talking_Head_Synthesis: Pytorch implementation of paper "One-Shot Free-View Neural Talking-Head Synthesis for Video Conferencing" 一种新颖…

缓存分布式一致性问题

缓存一致性问题发生的原因,是在更新数据时数据库和缓存数据的不一致。我们要做到保证缓存的最终一致性。如果数据需要强一致性建议直接查询数据库。 双写模式 双写模式为先写数据库,在写缓存。 进来两个请求,先执行“请求1”的操作写入数据…