设计模式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版》专栏!关注不迷路~

相关推荐
光亮的程序猿10 分钟前
confluent-kafka入门教程
python·kafka
三天不学习17 分钟前
Python快速入门指南:从零开始掌握Python编程
开发语言·python
大数据魔法师32 分钟前
豆瓣图书数据采集与可视化分析
python·数据分析·数据可视化
批量小王子32 分钟前
第1个小脚本:英语单语按字母个数进行升序排序
python
AmazingKO1 小时前
制作像素风《饥荒》类游戏的整体蓝图和流程
人工智能·python·游戏·docker·visual studio code·竹相左边
趣谈AI1 小时前
使用Trae编辑器开发Python Api (FastApi 框架)
python·编辑器·fastapi
carpell1 小时前
二叉树实战篇2
python·二叉树·数据结构与算法
python_chai1 小时前
Python网络编程从入门到精通:Socket核心技术+TCP/UDP实战详解
网络·python·tcp/ip·udp·socket
一只名叫Me的猫1 小时前
conda 创建、激活、退出、删除环境命令
python·conda
Steve lu2 小时前
PyTorch逻辑回归总结
人工智能·pytorch·python·深度学习·逻辑回归·原力计划