Go 设计模式中享元模式

鱼弦:CSDN内容合伙人、CSDN新星导师、51CTO(Top红人+专家博主) 、github开源爱好者(go-zero源码二次开发、游戏后端架构 https://github.com/Peakchen)

享元模式原理详细解释:
享元模式(Flyweight Pattern)是一种结构型设计模式,用于有效地支持大量细粒度对象的共享。享元模式通过共享对象的方式来减少内存使用和提高性能。

享元模式的核心思想是将对象分为可共享的内部状态(Intrinsic State)和不可共享的外部状态(Extrinsic State)。内部状态是对象的固定部分,可以被多个对象共享;而外部状态是对象的变化部分,每个对象都有自己的外部状态。

享元模式的关键在于共享对象。当需要创建一个新对象时,先检查是否已经存在具有相同内部状态的对象。如果存在,则直接返回现有对象;如果不存在,则创建新的对象并将其添加到共享池中,以备以后使用。

通过共享对象,享元模式可以显著减少内存使用,特别是当需要大量相似对象时。它适用于需要创建大量细粒度对象,并且对象之间有很多共享状态的情况。

底层结构图:
以下是享元模式的经典结构图:

+----------------------------+
|          Client            |
+----------------------------+
| - externalState          |
| + Operation()               |
+----------------------------+

        ^
        |
        |
        |
        |
        v

+----------------------------+
|         Flyweight         |
+----------------------------+
| + Operation(externalState) |
+----------------------------+

        ^
        |
        |
        |
        |
        v

+----------------------------+
|    ConcreteFlyweight  |
+----------------------------+
| + Operation(externalState) |
+----------------------------+

在上述结构图中,Client 是客户端,它通过调用 Operation() 方法来操作享元对象。

Flyweight 是享元接口,定义了操作享元对象的方法。

ConcreteFlyweight 是具体享元,实现了享元接口的 Operation() 方法,并包含内部状态。

使用场景解释:
享元模式适用于以下场景:

  1. 当需要创建大量细粒度的对象,并且这些对象可以共享部分或全部状态时,可以使用享元模式。通过共享对象,可以减少内存使用和提高性能。
  2. 当对象的大部分状态可以被外部状态替代时,可以使用享元模式。外部状态可以在运行时动态传递给享元对象,从而避免创建大量具有相同内部状态的对象。

代码示例实现:
以下是一个使用Go语言实现享元模式的示例:

package main

import "fmt"

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

// ConcreteFlyweight 具体享元
type ConcreteFlyweight struct {
	internalState string
}

// Operation 操作享元对象
func (f *ConcreteFlyweight) Operation(externalState string) {
	fmt.Printf("Internal state: %s, External state: %s\n", f.internalState, externalState)
}

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

// GetFlyweight 获取享元对象
func (ff *FlyweightFactory) GetFlyweight(key string) Flyweight {
	if flyweight, ok := ff.flyweights[key]; ok {
		return flyweight
	}

	flyweight := &ConcreteFlyweight{internalState: key}
	ff.flyweights[key] = flyweight
	return flyweight
}

func main() {
	factory := &FlyweightFactory{
		flyweights: make(map[string]Flyweight),
	}

	flyweight1 := factory.GetFlyweight("key1")
	flyweight1.Operation("state1")

	flyweight2 := factory.GetFlyweight("key2")
	flyweight2.Operation("state2")

	flyweight3 := factory.GetFlyweight("key1")
	flyweight3.Operation("state3")
}

在上述示例中,我们定义了享元接口(Flyweight)和具体享元(ConcreteFlyweight)。享元接口定义了操作享元对象的方法,具体享元实现了该接口并包含内部状态。享元工厂(FlyweightFactory)负责创建和管理享元对象。

在 main 函数中,我们通过享元工厂获取享元对象,并调用其 Operation 方法来操作对象。注意到当获取相同的内部状态时,工厂会返回同一个享元对象,实现了对象的共享。

文献材料链接:
以下是一些关于享元模式的参考文献链接:

  • Design Patterns: Elements of Reusable Object-Oriented Software(《设计模式:可复用面向对象软件的基础》)- GoF(Gang of Four)书籍:链接
  • Flyweight Design Pattern - GeeksforGeeks: 链接
  • Flyweight Design Pattern - TutorialsPoint: 链接
  • Flyweight Design Pattern - Refactoring Guru: 链接

当前都有哪些产品在使用:
享元模式是一种常用的设计模式,许多软件和框架都使用了该模式。以下是一些使用享元模式的产品和工具的示例:

  1. Java中的String类:String类是不可变的,当创建多个具有相同值的字符串时,它们会共享同一个字符串常量池中的对象。
  2. 数据库连接池:在数据库连接池中,连接对象是重量级的资源,通过使用享元模式,可以共享和重复使用连接对象,降低创建和销毁连接的开销。
  3. 图形库和游戏引擎:在图形库和游戏引擎中,图形对象和粒子对象通常是细粒度的,可以使用享元模式来共享和复用这些对象,提高性能。

猜你喜欢

转载自blog.csdn.net/feng1790291543/article/details/132159630