設計模式學習-使用go實現享元模式

享元模式

定義

享元模式(Flyweight),運用共享技術有效的支援大量細粒度的對象。

享元模式的意圖是復用對象,節省記憶體,前提是享元對象是不可變對象。就是當一個系統中有大量的重複對象的時候,如果這些對象是不可變對象,我們就可以使用
享元模式,將這些對象設計成享元,在記憶體只保存一份,供需要的程式碼使用,這樣能減少記憶體中對象的數量,起到節省記憶體的作用。實際上,不僅僅相同對象可以設計成享元,對於相似對象,我們也可以將這些對象中相同的部分(欄位)提取出來,設計成享元,讓這些大量相似對象引用這些享元。

不可變對象是函數初始化之後,他的狀態不會改變了,也就是不會存在被修改的情況。

優點

大大減少對象的創建,降低系統的記憶體,使效率提高。

缺點

提高了系統的複雜度

適用場景

一個系統中有大量相同或者相似的對象,使用這些對象,會造成記憶體的大量消耗,這時候可以考慮使用享元模式

程式碼實現

我們都下過象棋,對於象棋一共有32枚棋子,每方各16枚。每次下棋使用的都是這32枚棋子,只是每次移動的棋子的位置。

那麼這32枚棋子就可以作為享元,每次下棋就不用重新初始化生成棋子。只需在棋盤中放置棋子的位子,下棋的時候,更改位置即可。

// ChessPieceUnit ...
type ChessPieceUnit struct {
	id    int
	text  string
	color string
}

var pieces map[int]*ChessPieceUnit

func init() {
	pieces = make(map[int]*ChessPieceUnit, 32)
	pieces[1] = &ChessPieceUnit{
		id:    1,
		text:  "馬",
		color: "BLACK",
	}
	pieces[2] = &ChessPieceUnit{
		id:    2,
		text:  "炮",
		color: "BLACK",
	}
	// ...
}

func getChessPiece(chessPieceId int) *ChessPieceUnit {
	return pieces[chessPieceId]
}

type ChessPiece struct {
	chessPieceUnit *ChessPieceUnit
	positionX      int
	positionY      int
}

func newChessPiece(chessPieceId int, positionX, positionY int) *ChessPiece {
	return &ChessPiece{
		chessPieceUnit: getChessPiece(chessPieceId),
		positionX:      positionX,
		positionY:      positionY,
	}
}

// 棋盤
type ChessBoard struct {
	chessPieces map[int]*ChessPiece
}

func (cb *ChessBoard) InitChessBoard() {
	cb.chessPieces = make(map[int]*ChessPiece, 32)
	cb.chessPieces[1] = newChessPiece(1, 0, 1)
	cb.chessPieces[2] = newChessPiece(2, 0, 2)
	// ...
}

// Move 下棋
func (cb *ChessBoard) Move(chessPieceId int, positionX, positionY int) {
	// TODO
}

享元模式和單例模式的區別

單例模式:一個類只能創建一個對象。

享元模式:一個類可以創建多個對象,每個對象被多處程式碼引用共享。實際上,享元模式有點類似於之前講到的單例的變體:多例。

單例對象可以是可變的。 享元對象是不可變的。

實現上差不多,不過設計意圖不同,享元模式是為了對象復用,節省記憶體,而應用多例模式是為了限制對象的個數。

參考

【文中程式碼】//github.com/boilingfrog/design-pattern-learning/tree/master/享元模式
【大話設計模式】//book.douban.com/subject/2334288/
【極客時間】//time.geekbang.org/column/intro/100039001
【享元模式】//boilingfrog.github.io/2021/11/17/使用go實現享元模式/