Golang学习笔记_38——享元模式

server/2025/2/26 10:52:48/

Golang学习笔记_35——代理模式
Golang学习笔记_36——装饰器模式
Golang学习笔记_37——外观模式


文章目录

    • 享元模式(Flyweight Pattern)详解
      • 一、核心概念
        • 1. 定义
        • 2. 解决的问题
        • 3. 核心角色
        • 4. 类图
      • 二、特点分析
      • 三、适用场景
        • 1. 文字编辑器
        • 2. 游戏开发
        • 3. 数据库连接池
      • 四、代码示例(Go语言)
        • 场景:游戏子弹系统
      • 五、高级应用
      • 六、与其他模式对比
      • 七、总结


享元模式(Flyweight Pattern)详解

一、核心概念

1. 定义

享元模式是一种结构型设计模式,通过共享对象来有效支持大量细粒度对象的复用,从而减少内存占用和提高性能。其核心在于区分:

  • 内部状态(Intrinsic):可共享的固定属性(如字符编码、颜色配置)
  • 外部状态(Extrinsic):不可共享的运行时上下文(如坐标位置、字体大小)
2. 解决的问题
  • 内存资源浪费:大量相似对象导致内存占用过高
  • 对象创建开销:高频创建销毁对象影响性能
  • 状态分离管理:需要区分对象固定属性与可变属性
3. 核心角色
  1. Flyweight(抽象享元)
    定义对象接口,声明接收外部状态的方法(如Draw(x,y)

  2. ConcreteFlyweight(具体享元)
    实现抽象接口,存储内部状态(如字符编码)

  3. FlyweightFactory(享元工厂)
    创建并管理享元对象池,确保对象复用

  4. Client(客户端)
    维护外部状态并传递给享元对象

4. 类图

<a class=享元模式类图" />

@startuml
class FlyweightFactory {- pool: map[string]Flyweight+ GetFlyweight(key): Flyweight
}interface Flyweight {+ Operation(extrinsicState)
}class ConcreteFlyweight {- intrinsicState: string+ Operation(extrinsicState)
}FlyweightFactory o--> Flyweight : manages
Flyweight <|.. ConcreteFlyweight
@enduml

二、特点分析

优点

  1. 内存优化:减少重复对象的存储开销
  2. 性能提升:降低对象创建/销毁频率
  3. 状态解耦:清晰分离内部/外部状态

缺点

  1. 复杂度增加:需要严格区分内外状态
  2. 线程安全问题:共享对象需考虑并发访问
  3. 过度优化风险:不适合对象差异大的场景

三、适用场景

1. 文字编辑器
  • 内部状态:字符编码、字体样式
  • 外部状态:坐标位置、颜色
  • 效果:10万个’A’字符只需1个享元对象
2. 游戏开发
  • 内部状态:子弹贴图、伤害值
  • 外部状态:发射位置、移动轨迹
  • 效果:百万子弹共享10种类型配置
3. 数据库连接池
  • 内部状态:连接配置参数
  • 外部状态:当前事务状态
  • 效果:复用连接避免重复创建

四、代码示例(Go语言)

场景:游戏子弹系统

示例类图

@startumlclass BulletType {- name: string- color: string- texture: []byte+ String(): string
}class BulletFactory {- pool: map[string]*BulletType- mu: sync.Mutex+ GetBulletType(name: string, color: string): *BulletType
}class Bullet {- typeInfo: *BulletType- x: float64- y: float64- speed: float64+ String(): string
}BulletFactory "1" o-- "many" BulletType : contains > pool
Bullet --> BulletType : typeInfo >note left of BulletFactory<<Singleton>>Use GetBulletFactory() methodto get the single instance
end note@enduml
package flyweight_demoimport ("fmt""sync"
)// BulletType 享元对象 子弹类型(内部状态)
type BulletType struct {name    stringcolor   stringtexture []byte
}func (bt *BulletType) String() string {return fmt.Sprintf("%s-%s", bt.name, bt.color)
}// 享元工厂
type BulletFactory struct {pool map[string]*BulletTypemu   sync.Mutex
}var instance *BulletFactory
var once sync.Oncefunc GetBulletFactory() *BulletFactory {once.Do(func() {instance = &BulletFactory{pool: make(map[string]*BulletType),}})return instance
}func (bf *BulletFactory) GetBulletType(name, color string) *BulletType {key := name + "-" + colorbf.mu.Lock()defer bf.mu.Unlock()if bt, ok := bf.pool[key]; ok {return bt}newBt := &BulletType{name:    name,color:   color,texture: make([]byte, 1024*1024),}bf.pool[key] = newBtreturn newBt
}// 具体子弹对象(包含外部状态)
type Bullet struct {typeInfo *BulletTypex, y     float64speed    float64
}func newBullet(name, color string, x, y, speed float64) *Bullet {factory := GetBulletFactory()return &Bullet{typeInfo: factory.GetBulletType(name, color),x:        x,y:        y,speed:    speed,}
}func (b *Bullet) String() string {return fmt.Sprintf("%s @(%.1f,%.1f) speed=%.1f",b.typeInfo, b.x, b.y, b.speed)
}func test() {bullets := make([]*Bullet, 0)// 创建10000发子弹,实际只生成2种BulletTypefor i := 0; i < 5000; i++ {bullets = append(bullets,newBullet("AK47", "gold", float64(i), 0, 10),newBullet("M4A1", "silver", float64(i), 10, 12),)}// 验证对象复用fmt.Printf("Total bullet types created: %d\n",len(GetBulletFactory().pool)) // 输出2fmt.Println(bullets[0].String()) // AK47-gold @(0.0,0.0) speed=10.0fmt.Println(bullets[1].String()) // M4A1-silver @(0.0,10.0) speed=12.0
}
=== RUN   Test_test
Total bullet types created: 2
AK47-gold @(0.0,0.0) speed=10.0
M4A1-silver @(0.0,10.0) speed=12.0
--- PASS: Test_test (0.00s)
PASS

五、高级应用

1. 组合享元模式
type WeaponSkin struct {baseType *BulletTypesticker  string // 扩展装饰属性
}func (ws *WeaponSkin) GetKey() string {return ws.baseType.name + "_" + ws.baseType.color + "_" + ws.sticker
}
2. 线程安全优化
// 使用RWMutex提升并发性能
func (bf *BulletFactory) GetBulletTypeSafe(name, color string) *BulletType {key := name + "_" + color// 先尝试读锁bf.mu.RLock()if bt, exists := bf.pool[key]; exists {bf.mu.RUnlock()return bt}bf.mu.RUnlock()// 获取写锁bf.mu.Lock()defer bf.mu.Unlock()// 双检锁防止重复创建if bt, exists := bf.pool[key]; exists {return bt}newBt := createNewBulletType(name, color)bf.pool[key] = newBtreturn newBt
}

六、与其他模式对比

模式核心目标关键区别
单例模式控制实例数量享元管理多个共享对象
对象池模式复用昂贵对象享元侧重状态分离
装饰器模式动态扩展功能享元侧重对象复用

七、总结

享元模式通过共享细粒度对象,有效解决了:

  1. 内存占用问题:减少重复对象的存储
  2. 性能优化问题:降低对象创建开销
  3. 状态管理问题:明确区分内外状态

在Go语言中实现时需注意:

  • 使用sync.Mapmutex保证线程安全
  • 严格分离内部/外部状态
  • 合理设计对象键值(如颜色+名称组合键)

实际应用场景建议:

  • 游戏开发中的粒子系统
  • GUI系统的控件复用
  • 金融交易中的报价对象池

http://www.ppmy.cn/server/170721.html

相关文章

嵌入式项目:STM32刷卡指纹智能门禁系统

本文详细介绍基于STM32的刷卡指纹智能门禁系统。 获取资料/指导答疑/技术交流/选题/帮助&#xff0c;请点链接&#xff1a; https://gitee.com/zengzhaorong/share_contact/blob/master/stm32.txt 1 系统功能 1.1 功能概述 本系统由STM32硬件端&#xff08;下位机&#xff09;…

Spring Boot中@EnableAutoConfiguration的魔法与实例解析

在Spring Boot的世界里&#xff0c;EnableAutoConfiguration注解扮演着一个极为重要的角色。它不仅简化了Spring应用的配置过程&#xff0c;还通过智能的自动配置机制&#xff0c;让开发者能够更加专注于业务逻辑的实现&#xff0c;而无需过多地操心底层的配置细节。今天&#…

力扣 下一个排列

交换位置&#xff0c;双指针&#xff0c;排序。 题目 下一个排列即在组成的排列中的下一个大的数&#xff0c;然后当这个排列为降序时即这个排列最大&#xff0c;因为大的数在前面&#xff0c;降序排列的下一个数即升序。所以&#xff0c;要是想找到当前排列的下一个排列&…

算法与数据结构(格雷编码)

题目 思路 首先我们先看一下格雷编码的一些情况&#xff0c;为了一会方便理解&#xff0c;我们看它的二进制情况。 当n1时&#xff0c;输出[0&#xff0c;1] 当n2时&#xff0c;输出[00,01,11,10] 当n3时&#xff0c;输出[000, 001, 011, 010, 110, 111, 101, 100] 我们可…

lua基础语法学习

lua基础语法学习 文章目录 lua基础语法学习1. 基础2. 输入输出3. 分支结构与循环结构4. 函数5. 元表与元方法6. 面向对象 1. 基础 注释 --单行注释--[[ 多行注释 --]]标识符 标识符以一个字母 A 到 Z 或 a 到 z 或下划线 _ 开头后加上 0 个或多个字母&#xff0c;下划线&…

C#中级教程(1)——解锁 C# 编程的调试与错误处理秘籍

一、认识错误&#xff1a;编程路上的 “绊脚石” 在 C# 编程中&#xff0c;错误大致可分为两类&#xff1a;语法错误和语义错误&#xff08;逻辑错误&#xff09;。语法错误就像是写作文时的错别字和病句&#xff0c;编译器一眼就能识别出来&#xff0c;比如变量名拼写错误、符…

【大模型】Ubuntu下 fastgpt 的部署和使用

前言 本次安装的版本为 fastgpt:v4.8.8-fix2。 最新版本fastgpt:v4.8.20-fix2 问答时报错&#xff0c;本着跑通先使用起来&#xff0c;就没有死磕下去&#xff0c;后面bug解了再进行记录。   github连接&#xff1a;https://github.com/labring/FastGPT fastgpt 安装说明&…

Android平台GB28181接入模块(SmartGBD)技术接入说明

一、技术背景 GB/T 28181-2016/2022是中国国家标准&#xff0c;旨在规范网络视频监控设备的接入与互操作性。本模块的设计目标是使不具备国标音视频能力的 Android 终端能够通过平台注册接入到现有的GB/T 28181-2016/2022服务平台。该模块可广泛应用于智能监控、智慧零售、智慧…