5种创建型设计模式笔记(Python实现)

news/2025/3/10 15:33:09/文章来源:https://www.cnblogs.com/linsuiyuan/p/18762800

引言

本文主要讲设计模式中的5种创建型设计模式,代码采用 Python 实现,以加深对设计模式和 Python 的理解,同时也可以作为笔记以便以后查看。代码实现主要参考张伟老师写的《设计模式的艺术》。

单例模式

定义:

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。

优点:

  • 节省资源: 由于只有一个实例,可以减少内存占用,特别是在创建实例开销较大的情况下。
  • 全局访问: 提供了一个全局唯一的访问点,方便在程序的任何地方使用。
  • 控制共享资源: 可以有效地控制对共享资源的并发访问。

缺点:

  • 违背单一职责原则: 单例类既负责创建自身实例,又负责提供业务功能。
  • 难以测试: 由于全局唯一性,可能导致测试时的依赖关系复杂化。
  • 并发问题: 在多线程环境下,需要考虑线程安全问题。
  • 可扩展性差: 不利于扩展,如果需要修改单例类的行为,可能会影响到所有使用它的地方。

适用场景:

  • 需要频繁创建和销毁的对象,如线程池、数据库连接池。
  • 系统中只需要一个实例的类,如配置管理器、日志记录器。
  • 需要控制对共享资源的访问,如计数器、序列生成器。

代码实现:

Python 有多种实现单例的方式,这里采用类属性创建单例的方式。在类中定义一个类属性来存储实例,并在 __new__ 方法中控制实例的创建,同时使用线程锁来保证线程安全,代码如下:

import threading  class Singleton:  _instance = None  _lock = threading.Lock()  def __new__(cls, *args, **kwargs):  if not cls._instance:  with cls._lock:  if not cls._instance:  cls._instance = super(Singleton, cls).__new__(cls)  return cls._instance  singleton1 = Singleton()  
singleton2 = Singleton()  
assert singleton1 is singleton2

工厂方法模式

定义:

工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但将实际创建哪个类的决定延迟到子类中。换句话说,父类定义了创建对象的通用方法,而子类决定要创建哪个具体类的实例。

优点:

  • 符合开闭原则: 当需要增加新的产品时,只需要增加相应的具体工厂和具体产品,而不需要修改已有的代码。
  • 解耦: 将客户端代码与具体产品类解耦,客户端只需要知道抽象产品和抽象工厂,而不需要知道具体产品的实现细节。
  • 提高代码的可扩展性: 使得系统更容易扩展,可以方便地添加新的产品和工厂。

缺点:

  • 增加类的数量: 每增加一个产品,就需要增加一个具体产品类和一个具体工厂类,这会增加系统的复杂性。
  • 增加了系统的抽象性和实现的难度: 需要理解抽象工厂、抽象产品、具体工厂和具体产品之间的关系。

适用场景:

  • 当一个类不知道它所必须创建的对象的类的时候。
  • 当一个类希望由它的子类来指定它所创建的对象的时候。
  • 当需要将对象的创建与使用分离时。
  • 当需要提供一个产品类的库,而只想显示它们的接口而不是实现时。

代码实现:

这里使用日志记录器的例子来说明工厂方法模式。

Logger 接口充当抽象产品,其子类 FileLogger 和 DatabaseLogger 充当具体产品。LoggerFactory 接口充当抽象工厂,其子类 FileLoggerFactory 和 DatabaseLoggerFactory 充当具体工厂。

完整代码如下:

from abc import ABC, abstractmethod  # 日志记录器接口:抽象产品  
class Logger(ABC):  @abstractmethod  def log(self):  pass  # 日志记录器工厂接口:抽象工厂  
class LoggerFactory(ABC):  @abstractmethod  def create_logger(self) -> Logger:  pass  # 数据库日志记录器:具体产品  
class DatabaseLogger(Logger):  def log(self):  print("数据库日志记录。")  # 数据库日志记录器工厂类:具体工厂  
class DatabaseLoggerFactory(LoggerFactory):  def create_logger(self) -> Logger:  # 连接数据库,代码省略  dblogger = DatabaseLogger()  # 初始化日志记录器  ...  return dblogger  # 文件日志记录器:具体产品  
class FileLogger(Logger):  def log(self):  print("文件日志记录。")  # 文件日志记录器工厂类:具体工厂  
class FileLoggerFactory(LoggerFactory):  def create_logger(self) -> Logger:  flogger = FileLogger()  # 初始化日志记录器  ...  return flogger  if __name__ == "__main__":  factory = FileLoggerFactory()  logger = factory.create_logger()  logger.log()

抽象工厂模式

定义:

抽象工厂模式是一种创建型设计模式,它提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。简单来说,抽象工厂模式可以创建一系列产品族,每个产品族包含多个相关产品。

优点:

  • 隔离具体类: 客户端代码与具体产品类解耦,只需与抽象工厂和抽象产品交互。
  • 易于替换产品族: 可以轻松替换整个产品族,而无需修改客户端代码。
  • 保证产品一致性: 确保同一产品族的产品一起使用。

缺点:

  • 增加系统复杂性: 需要定义多个抽象类和具体类,增加了系统的复杂性。
  • 难以支持新种类的产品: 如果需要添加新的产品种类,可能需要修改抽象工厂接口,影响所有具体工厂。

适用场景:

  • 当系统需要独立于其产品的创建、组合和表示时。
  • 当系统需要支持多个产品族时。
  • 当需要保证同一产品族的产品一起使用时。
  • 当需要在运行时切换产品族时。

代码实现:

这里使用界面皮肤库的例子来实现抽象工厂模式。

抽象类 SkinFactory 充当抽象工厂,其子类 SpringSkinFactory 和 SummerSkinFactory 充当具体工厂。抽象类 Button、TextField 和 ComboBox 充当抽象产品,其子类 SpringButton、SpringTextField 和 SummerButton、SummerTextField 充当具体产品。

完整代码如下:

from abc import ABC, abstractmethod  class Button(ABC):  @abstractmethod  def display(self):  pass  class SpringButton(Button):  def display(self):  print("显示浅绿色按钮。")  class SummerButton(Button):  def display(self):  print("显示浅蓝色按钮。")  class TextField(ABC):  @abstractmethod  def display(self):  pass  class SpringTextField(TextField):  def display(self):  print("显示绿色边框文本框。")  class SummerTextField(TextField):  def display(self):  print("显示蓝色边框文本框。")  class SkinFactory(ABC):  @abstractmethod  def create_button(self) -> Button:  pass  @abstractmethod  def create_text_field(self) -> TextField:  pass  class SpringSkinFactory(SkinFactory):  def create_button(self) -> Button:  return SpringButton()  def create_text_field(self) -> TextField:  return SpringTextField()  class SummerSkingFactory(SkinFactory):  def create_button(self) -> Button:  return SummerButton()  def create_text_field(self) -> TextField:  return SummerTextField()  if __name__ == "__main__":  factory = SpringSkinFactory()  bt = factory.create_button()  tf = factory.create_text_field()  bt.display()  tf.display()

原型模式

定义:

原型模式是一种创建型设计模式,它通过复制现有对象(原型)来创建新对象,而无需知道其具体类。简单来说,就是“克隆”对象。

优点:

  • 性能提升: 对于创建复杂或耗时的对象,克隆现有实例比重新创建更高效。
  • 简化创建: 可以避免复杂的对象初始化过程。
  • 动态创建: 可以在运行时动态创建对象,无需预先知道其具体类型。
  • 隐藏实现细节: 客户端无需知道对象创建的具体细节。

缺点:

  • 克隆复杂对象可能复杂: 对于包含循环引用或复杂引用的对象,深拷贝可能比较困难。
  • 需要实现克隆方法: 每个需要克隆的类都需要实现克隆方法,这可能会增加代码量。

适用场景:

  • 创建复杂对象开销较大时: 例如,从数据库读取数据或进行复杂计算后创建的对象。
  • 需要大量相似对象时: 例如,游戏中的角色或图形编辑器中的形状。
  • 需要隐藏对象创建细节时: 客户端只需要知道如何克隆对象,而不需要知道其具体实现。
  • 需要动态指定对象类型时: 在运行时添加或删除对象。

代码实现:

Python中有个 copy 模块,可以直接用来实现原型模式。浅拷贝使用 copy.copy() 方法,深拷贝使用 copy.deepcopy() 方法,如果需要自定义拷贝逻辑,可以定义一个 clone() 方法。

因为比较简单,这里没有给出相关的代码例子。

建造者模式

定义:

建造者模式是一种创建型设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。简单来说,就是将复杂对象的创建过程分解为多个简单的步骤,并由一个建造者来负责这些步骤的执行。

优点:

  • 分离构建与表示: 使得同样的构建过程可以创建不同的表示,提高了代码的灵活性。
  • 更好的控制构建过程: 可以精细地控制对象的创建过程,避免了复杂的构造函数。
  • 易于扩展: 可以方便地添加新的建造者,从而创建新的对象表示。
  • 代码清晰: 将复杂对象的构建步骤分解,使得代码更易于理解和维护。

缺点:

  • 增加类的数量: 需要定义抽象建造者、具体建造者和指挥者等多个类,增加了系统的复杂性。
  • 需要理解多个类之间的关系: 需要理解抽象建造者、具体建造者,指挥者和产品之间的关系。

适用场景:

  • 创建复杂对象,且对象的构建过程比较复杂时。
  • 需要创建多种不同表示的对象,且这些对象具有相似的构建过程时。
  • 需要隐藏对象的构建细节时。
  • 当一个类中有很多的参数,而很多的参数都具有默认值,为了避免写过多的构造函数的时候。

代码实现:

这里使用游戏角色的创建来实现建造者模式。

ActorController 充当指挥者,ActorBuilder 充当抽象建造者,HeroBuilder、AngelBuilder 充当具体建造者,Actor 充当复杂产品。

from abc import ABC, abstractmethod  
from dataclasses import dataclass  @dataclass  
class Actor:  type: str = None  sex: str = None  costume: str = None  class ActorBuilder(ABC):  actor: Actor = Actor()  @abstractmethod  def build_type(self): ...  @abstractmethod  def build_sex(self): ...  @abstractmethod  def build_costume(self): ...  def build(self):  return self.actor  class HeroBuilder(ActorBuilder):  def build_type(self):  self.actor.type = "英雄"  def build_sex(self):  self.actor.sex = "男"  def build_costume(self):  self.actor.costume = "盔甲"  class AngelBuilder(ActorBuilder):  def build_type(self):  self.actor.type = "天使"  def build_sex(self):  self.actor.sex = "女"  def build_costume(self):  self.actor.costume = "白裙"  class ActorController:  def construct(self, builder: ActorBuilder) -> Actor:  builder.build_type()  builder.build_sex()  builder.build_costume()  return builder.build()  if __name__ == "__main__":  builder = HeroBuilder()  actor = ActorController().construct(builder)  print(actor)

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

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

相关文章

源码安装Rpcapd,用于 wireshark 远程抓包

背景 libpcap 是一个基础且关键的网络数据包捕获库,为 Wireshark、tcpdump 等流行工具提供核心功能支持。其中,rpcapd(Remote Packet Capture Daemon)组件允许在远程系统上进行数据包捕获,这一功能让我们能够从一个中心位置监控多个远程网络接入点,而无需在每个监控点都部署…

3.10 计数基础排列与组合

1.1 基本计数原则:乘积法则 1.1.1总共有多少种不同的长度为7的位串(位串:可视为一个数组,长度为7) A:2^7=128 1.1.2 计数有穷集的子集|S|表示长度;幂集:幂集(Power Set)是集合论中的一个基本概念。给定一个集合 S,其幂集 P(S) 是包含 S 所有子集的集合,包括空集和 S…

Nginx 常用功能,反向代理笔记

前言 本文是runoob教程的搬运,稍微修改了原文中的一些错误拼写的问题,顺便对一些概念进行了更详细的解释,欢迎批评指正!Nginx常用功能Http代理,反向代理:作为web服务器最常用的功能之一,尤其是反向代理。 这里我给来2张图,对正向代理与反向代理做个诠释,具体细节,大家…

Oracle 19c 数据库实战:从单机部署到 DG 高可用架构搭建

前言:在当今数字化时代,数据已成为企业最宝贵的资产之一。而数据库作为数据存储和管理的核心工具,其重要性不言而喻。Oracle 数据库作为全球领先的商业数据库管理系统,以其卓越的性能、可靠性和强大的功能,广泛应用于企业的关键业务系统中。无论是大型企业的 ERP、CRM 系统…

002TypeScript开发实战

如果读取不到,情况下: 1、建好项目后我们在这里写一个ts语法,让项目跑起来npm run dev 2、在src中新建文件demo.vue

拯救你的排版噩梦,搞定Deepseek到WPS的完美转换!

我们在使用DeepSeek时,好不容易生成的文案复制到WPS之后,排版却全部乱掉了。别急,今天教你一招,让排版从此不再乱!第一步:下载LibreOffice。打开这个网址:http://www.libreoffice.org 点击顶部的“Download”,选择第一个菜单,然后点击黄色按钮开始下载。如果觉得浏览…

Deepseek学习随笔(16)--- 腾讯研究院发布:AI图景解码50个年度关键词(附网盘链接)

随着人工智能技术的迅猛发展,AI正在深刻改变我们的生活和工作方式。腾讯研究院发布的《AI图景解码50个年度关键词》报告,通过梳理50个关键词,全面展现了AI领域的最新进展、技术趋势和未来方向。这份报告不仅为AI从业者提供了宝贵的参考,也为普通读者打开了了解AI的窗口。本…

不再头痛!算法备案自评估报告要点分析

算法备案材料包含众多报告,其中最难的莫过于《算法安全自评估报告》。本人经手过几十份该材料,今天就结合个人经验总结下自评估报告的要点及一些容易踩的坑,希望可以帮助大家。有其它问题也可以参考这篇文章了解。 一、自评估报告常见问题 1、前后矛盾 报告内部的算法、风控…

C语言中标准输出的缓冲机制

什么是缓冲区 缓存区是内存空间的一部分,再内存中,内存空间会预留一定的存储空间,这些存储空间是用来缓冲输入和输出的数据,预留的这部分空间就叫做缓冲区。 其中缓冲区还会根据对应的是输入设备还是输出设备分为输入缓冲区和输出缓冲区。 为什么需要缓冲? 直接操作硬件(…

k8s回调函数-cnblog

回调函数 Kubernetes 为容器提供了生命周期回调。 回调使容器能够了解其管理生命周期中的事件,并在执行相应的生命周期回调时运行在处理程序中实现的代码。Kubernetes 支持 PostStart 和 PreStop 事件。 当一个容器启动后,Kubernetes 将立即发送 PostStart 事件;在容器被终结…

Transfomer 中的强制教学(Teacher Forcing)

在预测阶段, 我们希望输入 "天雷滚滚我好怕怕" 和 "[cls]" 能预测出下一个token: 劈 于是我们在训练阶段,我们的输入是 "天雷滚滚我好怕怕" 和 “[cls]劈得我浑身掉渣渣”, 由于我们希望"[cls]" 能预测出 “劈” 字。 我们在损失函…

jenkins安装后可用插件版本需要高版本的jenkins才能使用

首先我们直接用清华镜像源https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/,比如我们要找Jenkins2.429对应版本 emmmm,没有429,427凑合用吧 获取这个地址,放到updatesite 进服务器,找到default.json,替换掉它,然后重启jenkins。 cp default.json default.json.ba…