[go] 享元模式

简介: [go] 享元模式

享元模式


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


模型说明



  1. 享元模式只是一种优化。在应用该模式之前,你要确定程序中存在与大量类似对象同时占用内存相关的内存消耗问题,并且确保该问题无法使用其他更好的方式来解决。
  2. 享元(Flyweight)类包含原始对象中部分能在多个对象中共享的状态。同一享元对象可在许多不同情景中使用。享元中存储的状态被称为“内在状态”。传递给享元方法的状态被称为“外在状态”。
  3. 情景(Context)类包含原始对象中各不相同的外在状态。情景与享元对象组合在一起就能表示原始对象的全部状态。
  4. 通常情况下,原始对象的行为会保留在享元类中。因此调用享元方法必须提供部分外在状态作为参数。但你也可将行为移动到情景类中,然后将连入的享元作为单纯的数据对象。
  5. 客户端(Client)负责计算或存储享元的外在状态。在客户端看来,享元是一种可在运行时进行配置的模板对象,具体的配置方式为向其方法中传入一些情景数据参数。
  6. 享元工厂(Flyweight Factory)会对已有享元的缓存池进行管理。有了工厂后,客户端就无需直接创建享元,它们只需调用工厂并向其传递目标享元的一些内在状态即可。工厂会根据参数在之前已创建的享元中进行查找,如果找到满足条件的享元就将其返回;如果没有找到就根据参数新建享元。


优缺点


1.优点


  • 如果程序中有很多相似对象, 那么你将可以节省大量内存。


2.缺点


  • 你可能需要牺牲执行速度来换取内存,因为他人每次调用享元方法时都需要重新计算部分情景数据。
  • 代码会变得更加复杂。团队中的新成员总是会问:“为什么要像这样拆分一个实体的状态?”。


使用场景


  • 仅在程序必须支持大量对象且没有足够的内存容量时使用享元模式。


参考代码


假设目前有 5 名恐怖分子和 5 名反恐精英, 一共是 10 名玩家。 那么关于服装, 我们就有两个选项了。


  1. 10 个玩家对象各自创建不同的服装对象, 并将其嵌入。 总共会创建 10 个服装对象。
  2. 我们创建两个服装对象:
  • 单一恐怖分子服装对象: 其将在 5 名恐怖分子之间共享。
  • 单一反恐精英服装对象: 其将在 5 名反恐精英之间共享。


状态划分:


  • 内部状态:内部状态的服装可在多个恐怖分子和反恐精英对象间共享。
  • 外部状态:玩家位置和玩家所使用的武器就是外部状态, 因为其在每个对象中都是不同的。


dressFactory.go: 享元工厂


package main
import "fmt"
const (
  //TerroristDressType terrorist dress type
  TerroristDressType = "tDress"
  //CounterTerrroristDressType terrorist dress type
  CounterTerrroristDressType = "ctDress"
)
var (
  dressFactorySingleInstance = &DressFactory{
    dressMap: make(map[string]Dress),
  }
)
type DressFactory struct {
  dressMap map[string]Dress
}
func (d *DressFactory) getDressByType(dressType string) (Dress, error) {
  if d.dressMap[dressType] != nil {
    return d.dressMap[dressType], nil
  }
  if dressType == TerroristDressType {
    d.dressMap[dressType] = newTerroristDress()
    return d.dressMap[dressType], nil
  }
  if dressType == CounterTerrroristDressType {
    d.dressMap[dressType] = newCounterTerroristDress()
    return d.dressMap[dressType], nil
  }
  return nil, fmt.Errorf("Wrong dress type passed")
}
func getDressFactorySingleInstance() *DressFactory {
  return dressFactorySingleInstance
}


dress.go: 享元接口以及具体享元实现类


package main
type Dress interface {
  getColor() string
}
type TerroristDress struct {
  color string
}
func (t *TerroristDress) getColor() string {
  return t.color
}
func newTerroristDress() *TerroristDress {
  return &TerroristDress{color: "red"}
}
type CounterTerroristDress struct {
  color string
}
func (c *CounterTerroristDress) getColor() string {
  return c.color
}
func newCounterTerroristDress() *CounterTerroristDress {
  return &CounterTerroristDress{color: "green"}
}


player.go: 背景


package main
type Player struct {
    dress      Dress
    playerType string
    lat        int
    long       int
}
func newPlayer(playerType, dressType string) *Player {
    dress, _ := getDressFactorySingleInstance().getDressByType(dressType)
    return &Player{
        playerType: playerType,
        dress:      dress,
    }
}
func (p *Player) newLocation(lat, long int) {
    p.lat = lat
    p.long = long
}


game.go: 客户端代码


package main
type game struct {
    terrorists        []*Player
    counterTerrorists []*Player
}
func newGame() *game {
    return &game{
        terrorists:        make([]*Player, 1),
        counterTerrorists: make([]*Player, 1),
    }
}
func (c *game) addTerrorist(dressType string) {
    player := newPlayer("T", dressType)
    c.terrorists = append(c.terrorists, player)
    return
}
func (c *game) addCounterTerrorist(dressType string) {
    player := newPlayer("CT", dressType)
    c.counterTerrorists = append(c.counterTerrorists, player)
    return
}


main.go: 客户端代码


package main
import "fmt"
func main() {
    game := newGame()
    //Add Terrorist
    game.addTerrorist(TerroristDressType)
    game.addTerrorist(TerroristDressType)
    game.addTerrorist(TerroristDressType)
    game.addTerrorist(TerroristDressType)
    //Add CounterTerrorist
    game.addCounterTerrorist(CounterTerrroristDressType)
    game.addCounterTerrorist(CounterTerrroristDressType)
    game.addCounterTerrorist(CounterTerrroristDressType)
    dressFactoryInstance := getDressFactorySingleInstance()
    for dressType, dress := range dressFactoryInstance.dressMap {
        fmt.Printf("DressColorType: %s\nDressColor: %s\n", dressType, dress.getColor())
    }
}


output:


DressColorType: tDress
DressColor: red
DressColorType: ctDress
DressColor: green
相关文章
|
6月前
|
设计模式 Go
[设计模式 Go实现] 结构型~享元模式
[设计模式 Go实现] 结构型~享元模式
|
设计模式 存储 Go
Go语言实现设计模式之享元模式
享元模式是一种常用的设计模式,它通过共享对象来减少内存使用和提高性能。本文将详细介绍享元模式的概念和原理,并使用Go语言实现一个示例,以帮助读者更好地理解该设计模式的应用。
114 0
|
9天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
30 2
|
8天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
19 2
|
8天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
21 2
|
12天前
|
安全 Go
用 Zap 轻松搞定 Go 语言中的结构化日志
在现代应用程序开发中,日志记录至关重要。Go 语言中有许多日志库,而 Zap 因其高性能和灵活性脱颖而出。本文详细介绍如何在 Go 项目中使用 Zap 进行结构化日志记录,并展示如何定制日志输出,满足生产环境需求。通过基础示例、SugaredLogger 的便捷使用以及自定义日志配置,帮助你在实际开发中高效管理日志。
32 1
|
12天前
|
程序员 Go
go语言中的控制结构
【11月更文挑战第3天】
88 58
|
3天前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
16 4
|
3天前
|
缓存 监控 前端开发
在 Go 语言中实现 WebSocket 实时通信的应用,包括 WebSocket 的简介、Go 语言的优势、基本实现步骤、应用案例、注意事项及性能优化策略,旨在帮助开发者构建高效稳定的实时通信系统
本文深入探讨了在 Go 语言中实现 WebSocket 实时通信的应用,包括 WebSocket 的简介、Go 语言的优势、基本实现步骤、应用案例、注意事项及性能优化策略,旨在帮助开发者构建高效稳定的实时通信系统。
22 1
|
3天前
|
中间件 Go API
Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架
本文概述了Go语言中几种流行的Web框架,如Beego、Gin和Echo,分析了它们的特点、性能及适用场景,并讨论了如何根据项目需求、性能要求、团队经验和社区支持等因素选择最合适的框架。
12 1