Skip to content

享元模式 (Flyweight Pattern) ​

意图 ​

享元模式是一种结构型设计模式,通过共享对象减少内存占用,适合管理大量相似的对象。

问题 ​

在现实世界中,考虑一个图形编辑器的场景,该编辑器需要处理大量的图形对象,例如多个相同的图标。如果每个图形对象都独立存储,其内存消耗将会非常大。

解决方案 ​

使用享元模式,我们可以将相同的对象共享起来,只存储一个公共的共享部分,而将特有的、变化的部分存储在外部数据中。这样,可以显著减少对象的创建和内存消耗。

模式结构 ​

  1. 享元(Flyweight):定义对象的接口,可以提供一个共享的、可重用的对象。
  2. 具体享元(Concrete Flyweight):实现享元接口,定义对象的共享部分。
  3. 享元工厂(Flyweight Factory):管理享元对象的创建和共享,确保享元对象的共享和重用。
  4. 非共享享元(Unshared Flyweight):定义非共享部分的接口,用于存储对象的特有部分。

代码 ​

go
package main

import "fmt"

// 享元接口
type Flyweight interface {
    Operation(extrinsicState string)
}

// 具体享元 - 图标
type ConcreteFlyweight struct {
    intrinsicState string
}

func (f *ConcreteFlyweight) Operation(extrinsicState string) {
    fmt.Printf("图标状态: %s, 外部状态: %s\n", f.intrinsicState, extrinsicState)
}

// 享元工厂
type FlyweightFactory struct {
    flyweights map[string]Flyweight
}

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

func (f *FlyweightFactory) GetFlyweight(key string) Flyweight {
    if flyweight, exists := f.flyweights[key]; exists {
        return flyweight
    }
    // 创建新的享元对象并存储
    flyweight := &ConcreteFlyweight{intrinsicState: key}
    f.flyweights[key] = flyweight
    return flyweight
}

func main() {
    factory := NewFlyweightFactory()

    // 获取共享的享元对象
    flyweight1 := factory.GetFlyweight("图标1")
    flyweight2 := factory.GetFlyweight("图标2")
    flyweight3 := factory.GetFlyweight("图标1") // 重用已有的享元对象

    // 操作享元对象
    flyweight1.Operation("外部状态1")
    flyweight2.Operation("外部状态2")
    flyweight3.Operation("外部状态3")
}

适用场景 ​

  • 系统中有大量相似对象,独立存储内存开销大时。
  • 需要将对象的内外部状态分离,内外部状态的变化不会影响共享部分时。

实现方式 ​

  1. 定义享元接口,声明共享部分的操作。
  2. 创建具体享元类,实现享元接口,并定义共享部分。
  3. 创建享元工厂类,管理享元对象的创建和共享。
  4. 在客户端代码中,通过享元工厂获取共享对象并操作。

优缺点 ​

优点:

  • 相同对象只存一份,内存占用下降。
  • 由工厂复用对象,省掉重复创建的开销,需要时也能动态创建。

缺点:

  • 共享和管理策略要设计对,否则复用不上。
  • 享元工厂和享元对象之间的协调增加了一层复杂性。

其他模式的关系 ​

  • 享元模式与装饰器模式(Decorator Pattern):装饰器模式用于动态地为对象添加职责,而享元模式用于共享对象以减少内存占用。它们可以结合使用,例如在享元对象中应用装饰器来增强其功能。
  • 享元模式与代理模式(Proxy Pattern):代理模式用于控制对对象的访问,而享元模式用于共享对象以减少内存消耗。两者可以结合使用,例如通过代理模式访问享元对象。
  • 享元模式与组合模式(Composite Pattern):组合模式用于将对象组合成树形结构以表示部分-整体的层次结构,而享元模式用于减少大量相似对象的内存占用。在组合模式中,可以使用享元模式来管理和共享相似的叶子对象。

参考资料 ​

同层页面 ​

相关页面 ​

Hello Golang