设计模式Python版 享元模式

ops/2025/2/10 22:15:05/

文章目录


前言

GOF设计模式分三大类:

  • 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。
  • 结构型模式:关注类和对象之间的组合,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。
  • 行为型模式:关注对象之间的交互,包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。

一、享元模式

享元模式(Flyweight Pattern)

  • 定义:运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式。

  • 解决问题:如何实现对象的多次复用以节省系统资源?

  • 使用场景:

    • 一个系统有大量相同或者相似的对象,造成内存的大量耗费。
    • 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
    • 在使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源。因此,在需要多次重复使用同一享元对象时才值得使用享元模式
  • 组成:

    • Flyweight(抽象享元类):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法
    • ConcreteFlyweight(具体享元类):它实现了抽象享元类,其实例称为享元对象。可以结合单例模式来设计具体享元类。
    • UnsharedConcreteFlyweight(非共享具体享元类):并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类。
    • FlyweightFactory(享元工厂类):享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中。
  • 补充说明:

    • 在计算机内存中存储了多个完全相同或者非常相似的对象。利用享元模式,节约内存使用空间,实现对这些相同或者相似对象的共享访问。
    • 享元模式通过共享技术实现相同或相似对象的重用。享元模式以共享的方式高效地支持大量细粒度对象的重用。
    • 享元模式中,存储这些共享实例对象的地方称为享元池(Flyweight Pool)。享元池一般设计为一个存储“键值对”的集合,可以结合工厂模式进行设计。
    • 享元对象能做到共享的关键是区分了内部状态(Intrinsic State)和外部状态(Extrinsic State)。
      • 内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,内部状态可以共享。
      • 外部状态是随环境改变而改变的、不可以共享的状态。
    • 享元模式中引入了享元工厂类。享元工厂类的作用在于提供一个用于存储享元对象的享元池。当用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。
    • 享元模式的使用频率并不高
  • 优点:

    • 实现节约内存进而提高系统性能
    • 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
  • 缺点:

    • 享元模式需要分离出内部状态和外部状态,从而使得系统变得复杂
    • 为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。

在这里插入图片描述

二、享元模式示例

使用享元模式来设计围棋软件的棋子对象

  • 围棋棋盘中包含大量的黑子和白子,它们的形状、大小都一模一样,只是出现的位置不同而已。
  • IgoChessman充当抽象享元类,BlackIgoChessman和WhiteIgoChessman充当具体享元类,IgoChessmanFactory充当享元工厂类。带外部状态Coordinates坐标类,用于存储每一个棋子的位置。
  • 享元工厂类,使用单例模式
python">"""外部状态类:坐标"""class Coordinates:def __init__(self, x, y):self.x = xself.y = y"""抽象享元类"""class IgoChessman:def get_color(self) -> str:raise NotImplementedErrordef display(self, coord: Coordinates):print(f"棋子颜色:{self.get_color()},棋子位置:{coord.x,coord.y}")"""具体享元类"""class BlackIgoChessman(IgoChessman):def get_color(self):return "黑色"class WhiteIgoChessman(IgoChessman):def get_color(self):return "白色""""享元工厂:使用单例模式"""class IgoChessmanFactory:def __init__(self):self.pool = {}  # 享元池self.black = BlackIgoChessman()self.white = WhiteIgoChessman()self.pool["b"] = self.blackself.pool["w"] = self.whitedef get_igo_chessman(self, color) -> IgoChessman:# 通过key获取享元池中的享元对象return self.pool.get(color, None)factory = IgoChessmanFactory()
  • 客户端代码
python"># 客户端代码
from flyweights import factory, Coordinatesblack1 = factory.get_igo_chessman("b")
black2 = factory.get_igo_chessman("b")
black3 = factory.get_igo_chessman("b")
print(f"判断两颗黑子是否相同:{black1==black2}")white1 = factory.get_igo_chessman("w")
white2 = factory.get_igo_chessman("w")
print(f"判断两颗白子是否相同:{white1==white2}")black1.display(Coordinates(1, 2))
black2.display(Coordinates(3, 4))
black3.display(Coordinates(1, 3))
white1.display(Coordinates(2, 5))
white2.display(Coordinates(2, 4))
  • 输出结果
判断两颗黑子是否相同:True
判断两颗白子是否相同:True
棋子颜色:黑色,棋子位置:(1, 2)
棋子颜色:黑色,棋子位置:(3, 4)
棋子颜色:黑色,棋子位置:(1, 3)
棋子颜色:白色,棋子位置:(2, 5)
棋子颜色:白色,棋子位置:(2, 4)

您正在阅读的是《设计模式Python版》专栏!关注不迷路~


http://www.ppmy.cn/ops/157369.html

相关文章

如何通过PHP接入DeepSeek的API

想知道如何通过PHP接入DeepSeek的API。看起来他对之前的Python步骤比较熟悉,但这次想用PHP实现。 首先,我需要回顾一下DeepSeek API的文档,确认它支持哪些方法和参数。假设用户已经配置了环境变量,比如API密钥,接下来…

基于DeepSeek API和VSCode的自动化网页生成流程

1.创建API key 访问官网DeepSeek ,点击API开放平台。 在开放平台界面左侧点击API keys,进入API keys管理界面,点击创建API key按钮创建API key,名称自定义。 2.下载并安装配置编辑器VSCode 官网Visual Studio Code - Code Editing…

构建Ubuntu unminimized的docker镜像

前言 最近需要回顾一下Linux环境的Bash命令。使用 Docker 是快速搭建 Linux 环境的最佳方式,只需运行以下命令即可获取并启动一个 Ubuntu 容器: docker pull ubuntu docker run -it ubuntu 然而,Docker Hub 提供的官方 Ubuntu 镜像是一个最…

【机器学习案列】基于XGBoost的睡眠时间预测

🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

w196Spring Boot高校教师科研管理系统设计与实现

🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…

Leetcode面试经典150题刷题记录 —— 二分查找篇

Leetcode面试经典150题刷题记录-系列Leetcod面试经典150题刷题记录——数组 / 字符串篇Leetcod面试经典150题刷题记录 —— 双指针篇Leetcod面试经典150题刷题记录 —— 矩阵篇Leetcod面试经典150题刷题记录 —— 滑动窗口篇Leetcod面试经典150题刷题记录 —— 哈希表篇Leetcod…

c/c++蓝桥杯经典编程题100道(9)数组排序

数组排序 ->返回c/c蓝桥杯经典编程题100道-目录 目录 数组排序 一、题型解释 二、例题问题描述 三、C语言实现 解法1:冒泡排序(难度★) 解法2:选择排序(难度★) 解法3:快速排序&#…

selenium4.0 入门案例

from selenium import webdriver import time #创建webdriver对象,把驱动放置到了系统环境变量中,可不带参数创建 # driver webdriver.Firefox() driver webdriver.Chrome() #使用浏览器打开指定页面 driver.get(http://www.baidu.com)time.sleep(5) #回…