设计模式Python版 享元模式

文章目录


前言

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 = x
        self.y = y


"""抽象享元类"""


class IgoChessman:
    def get_color(self) -> str:
        raise NotImplementedError

    def 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.black
        self.pool["w"] = self.white

    def get_igo_chessman(self, color) -> IgoChessman:
        # 通过key获取享元池中的享元对象
        return self.pool.get(color, None)


factory = IgoChessmanFactory()
  • 客户端代码
python 复制代码
# 客户端代码
from flyweights import factory, Coordinates


black1 = 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))
  • 输出结果
sh 复制代码
判断两颗黑子是否相同:True
判断两颗白子是否相同:True
棋子颜色:黑色,棋子位置:(1, 2)
棋子颜色:黑色,棋子位置:(3, 4)
棋子颜色:黑色,棋子位置:(1, 3)
棋子颜色:白色,棋子位置:(2, 5)
棋子颜色:白色,棋子位置:(2, 4)

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

相关推荐
凤头百灵鸟8 分钟前
Python语法基础篇(包含类型转换、拷贝、可变对象/不可变对象,函数,拆包,异常,模块,闭包,装饰器)
python
多多*1 小时前
LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考
linux·开发语言·redis·python·bootstrap·lua
何双新2 小时前
第21讲、Odoo 18 配置机制详解
linux·python·开源
Wish3D2 小时前
阿里云OSS 上传文件 Python版本
开发语言·python·阿里云
阿福不是狗4 小时前
Python使用总结之Mac安装docker并配置wechaty
python·macos·docker
gen_5 小时前
mac环境下的python、pycharm和pip安装使用
python·macos·pycharm
AI视觉网奇5 小时前
pycharm 左右箭头 最近编辑
ide·python·pycharm
思绪无限5 小时前
Pycharm的终端无法使用Anaconda命令行问题详细解决教程
ide·python·pycharm·终端·命令行·anaconda·问题教程
漫步云端-r5 小时前
Pycharm的使用技巧总结
ide·python·pycharm
风逸hhh6 小时前
python打卡day46@浙大疏锦行
开发语言·python