文章目录
- 前言
- 一、享元模式
- 二、享元模式示例
前言
GOF设计模式分三大类:
- 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。
- 结构型模式:关注类和对象之间的组合,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。
- 行为型模式:关注对象之间的交互,包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。
一、享元模式
享元模式(Flyweight Pattern)
-
定义:运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式。
-
解决问题:如何实现对象的多次复用以节省系统资源?
-
使用场景:
- 一个系统有大量相同或者相似的对象,造成内存的大量耗费。
- 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
- 在使用享元模式时需要维护一个存储享元对象的享元池,而这需要耗费一定的系统资源。因此,在需要多次重复使用同一享元对象时才值得使用享元模式。
-
组成:
- Flyweight(抽象享元类):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法
- ConcreteFlyweight(具体享元类):它实现了抽象享元类,其实例称为享元对象。可以结合单例模式来设计具体享元类。
- UnsharedConcreteFlyweight(非共享具体享元类):并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类。
- FlyweightFactory(享元工厂类):享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中。
-
补充说明:
- 在计算机内存中存储了多个完全相同或者非常相似的对象。利用享元模式,节约内存使用空间,实现对这些相同或者相似对象的共享访问。
- 享元模式通过共享技术实现相同或相似对象的重用。享元模式以共享的方式高效地支持大量细粒度对象的重用。
- 享元模式中,存储这些共享实例对象的地方称为享元池(Flyweight Pool)。享元池一般设计为一个存储“键值对”的集合,可以结合工厂模式进行设计。
- 享元对象能做到共享的关键是区分了内部状态(Intrinsic State)和外部状态(Extrinsic State)。
- 内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,内部状态可以共享。
- 外部状态是随环境改变而改变的、不可以共享的状态。
- 在享元模式中引入了享元工厂类。享元工厂类的作用在于提供一个用于存储享元对象的享元池。当用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。
- 享元模式的使用频率并不高
-
优点:
- 实现节约内存进而提高系统性能
- 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
-
缺点:
- 享元模式需要分离出内部状态和外部状态,从而使得系统变得复杂
- 为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。
二、享元模式示例
使用享元模式来设计围棋软件的棋子对象
- 围棋棋盘中包含大量的黑子和白子,它们的形状、大小都一模一样,只是出现的位置不同而已。
- IgoChessman充当抽象享元类,BlackIgoChessman和WhiteIgoChessman充当具体享元类,IgoChessmanFactory充当享元工厂类。带外部状态Coordinates坐标类,用于存储每一个棋子的位置。
- 享元工厂类,使用单例模式
"""外部状态类:坐标"""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()
- 客户端代码
# 客户端代码
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版》专栏!关注不迷路~