本网站的中文版本尚处早期开发阶段。如果您发现其中存在错字、纰漏或其他任何问题,请随时联系向我反馈。
享元

Go 享元模式讲解和代码示例

享元是一种结构型设计模式 它允许你在消耗少量内存的情况下支持大量对象

模式通过共享多个对象的部分状态来实现上述功能 换句话来说 享元会将不同对象的相同数据进行缓存以节省内存

概念示例

在游戏 反恐精英 恐怖分子和反恐精英身着不同类型的衣物 为了简便起见 我们就假设双方都各有一种服装类型 服装对象嵌入在玩家对象之中 如下所示

下面是玩家的结构体 我们可以看到 服装对象是嵌入在玩家结构体之中的

type player struct {
dress      dress
playerType string // 可为 T 或 CT
lat        int
long       int
}

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

  1. 10 个玩家对象各自创建不同的服装对象 并将其嵌入 总共会创建 10 个服装对象

  2. 我们创建两个服装对象

  • 单一恐怖分子服装对象 其将在 5 名恐怖分子之间共享
  • 单一反恐精英服装对象 其将在 5 名反恐精英之间共享

你可以看到 方法 1 中我们总共创建了 10 个服装对象 方法 2 中则只有 2 个服装对象 第二种方法 就是我们所遵循的享元设计模式 我们所创建的 2 个服装对象被称为是享元对象

享元模式会从对象中提取出公共部分并创建享元对象 这些享元对象 服装 随后可在多个对象 玩家 中分享 这极大地减少了服装对象的数量 更棒的是即便你创建了更多玩家 也只需这么两个服装对象就足够了

在享元模式中 我们会将享元对象存储在 map 容器中 每当创建共享享元对象的其他对象时 都会从 map 容器中获取享元对象

下面让我们来看看此类安排的内部状态和外部状态

  • 内部状态 内部状态的服装可在多个恐怖分子和反恐精英对象间共享

  • 外部状态 玩家位置和玩家所使用的武器就是外部状态 因为其在每个对象中都是不同的

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
}

terroristDress.go: 具体享元对象

package main

type terroristDress struct {
	color string
}

func (t *terroristDress) getColor() string {
	return t.color
}

func newTerroristDress() *terroristDress {
	return &terroristDress{color: "red"}
}

counterTerroristDress.go: 具体享元对象

package main

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
}

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.txt: 执行结果

DressColorType: ctDress
DressColor: green
DressColorType: tDress
DressColor: red

享元在其他编程语言中的实现

Java 享元模式讲解和代码示例 C# 享元模式讲解和代码示例 C++ 享元模式讲解和代码示例 PHP 享元模式讲解和代码示例 Python 享元模式讲解和代码示例 Ruby 享元模式讲解和代码示例 Swift 享元模式讲解和代码示例 TypeScript 享元模式讲解和代码示例