设计模式-14-享元模式

享元模式是一种结构型设计模式, 它摒弃了在每个对象中保存所有数据的方式, 通过共享多个对象所共有的相同状态, 能在有限的内存容量中载入更多对象

逻辑结构

在享元模式中,有四个角色:

  • Flyweight(抽象享元):声明公共方法,这些方法可以向外界提供对象的内部状态。
  • ConcreteFlyweight(具体享元):实现抽象享元接口,保存对象内部状态,并且可以被共享。
  • FlyweightFactory(享元工厂):维护一个享元池(Flyweight Pool),用于存储已经创建的共享对象。客户端可以向工厂请求一个享元,如果工厂中不存在该享元,则创建新的享元并将其加入到享元池中;否则直接从享元池中返回已有的享元
Flyweight

代码实现

代码路径:https://github.com/XBoom/DesignPatterns/tree/main/13_Component

  1. 首先,定义公共方法,需要被享元的内容

    1
    2
    3
    4
    // Flyweight 是享元接口
    type Flyweight interface {
    Operation(extrinsicState string)
    }
  2. 然后定义具体的享元操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // ConcreteFlyweight 是具体享元类
    type ConcreteFlyweight struct {
    intrinsicState string
    }

    func NewConcreteFlyweight(intrinsicState string) *ConcreteFlyweight {
    return &ConcreteFlyweight{
    intrinsicState: intrinsicState,
    }
    }

    func (f *ConcreteFlyweight) Operation(extrinsicState string) {
    fmt.Printf("具体享元对象:内部状态为 %s,外部状态为 %s\n", f.intrinsicState, extrinsicState)
    }
  3. 第三步就是一个享元工厂

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // FlyweightFactory 是享元工厂类
    type FlyweightFactory struct {
    flyweights map[string]Flyweight
    }

    func NewFlyweightFactory() *FlyweightFactory {
    return &FlyweightFactory{
    flyweights: make(map[string]Flyweight),
    }
    }

    func (ff *FlyweightFactory) GetFlyweight(key string) Flyweight {
    if flyweight, ok := ff.flyweights[key]; ok {
    return flyweight
    }

    flyweight := NewConcreteFlyweight(key)
    ff.flyweights[key] = flyweight
    return flyweight
    }

执行

1
2
3
4
5
6
7
8
9
10
factory := NewFlyweightFactory()

flyweight1 := factory.GetFlyweight("A")
flyweight1.Operation("1")

flyweight2 := factory.GetFlyweight("B")
flyweight2.Operation("2")

flyweight3 := factory.GetFlyweight("A")
flyweight3.Operation("3")

结果

1
2
3
具体享元对象:内部状态为 A,外部状态为 1
具体享元对象:内部状态为 B,外部状态为 2
具体享元对象:内部状态为 A,外部状态为 3

总结

  1. 仅在程序必须支持大量对象且没有足够的内存容量时使用享元模式(类似与内存池,但是这个重复利用的不是分配的内存而是对象)
  2. 享元中共享的是对象,如果对象多处使用修改对象内容需要注意(类似指针),其次需要考虑并发处理
  3. 好处就是减少了内存使用,但这种适用的是常驻对象,临时对象需要考虑内存上限与过期删除问题
  4. 有一个类似的 共享调用 共享的是请求也可以看看

参考链接

  1. https://refactoringguru.cn/design-patterns/flyweight
  2. https://lailin.xyz/post/flyweight.html