文章目录
前言
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版》专栏!关注不迷路~