文章目录
- 十一、flyweight
-
- [11.1 pool 连接池](#11.1 pool 连接池)
-
- [11.1.1 pool_test.go](#11.1.1 pool_test.go)
- [11.1.2 pool.go](#11.1.2 pool.go)
- [11.1.3 conn.go](#11.1.3 conn.go)
- [11.2 chess_board](#11.2 chess_board)
-
- [11.2.1 chess_test.go](#11.2.1 chess_test.go)
- [11.2.2 chess.go](#11.2.2 chess.go)
十一、flyweight
https://refactoringguru.cn/design-patterns/flyweight
大量重复的对象, 如果很消耗资源, 没必要每次都初始化, 可以共用, 共享. 这就是 flyweight 享元模式.
各种池技术: 线程池, 数据库连接池, http 网络连接池, 都是应用场景
参考: 共享单车示例
11.1 pool 连接池
bash
11flyweight/111pool
├── conn.go
├── pool.go
├── pool_test.go
└── readme.md
11.1.1 pool_test.go
go
package _11pool
import (
"github.com/stretchr/testify/require"
"testing"
)
/*
=== RUN TestPoolWithSize1
[连接池] 申请连接资源, 开始
[连接池] 申请连接资源, 成功
数据库连接池: 连接中...
[连接池] 申请连接资源, 开始
[连接池] 归还连接资源, 成功
[连接池] 申请连接资源, 开始
[连接池] 申请连接资源, 成功
数据库连接池: 连接中...
--- PASS: TestPoolWithSize1 (0.00s)
PASS
*/
func TestPoolWithSize1(t *testing.T) {
conns := []conn{&dbConn{}}
p := NewPool(conns)
c1, err := p.getConn()
require.NoError(t, err)
require.NotNil(t, c1)
c1.connect()
c2, err := p.getConn()
require.Error(t, err)
require.Nil(t, c2)
p.putConn(c1)
c3, err := p.getConn()
require.NoError(t, err)
require.NotNil(t, c3)
c3.connect()
}
/*
=== RUN TestPoolWithSize5
[连接池] 申请连接资源, 开始
[连接池] 申请连接资源, 成功
数据库连接池: 连接中...
[连接池] 归还连接资源, 成功
[连接池] 申请连接资源, 开始
[连接池] 申请连接资源, 成功
数据库连接池: 连接中...
[连接池] 归还连接资源, 成功
[连接池] 申请连接资源, 开始
[连接池] 申请连接资源, 成功
数据库连接池: 连接中...
[连接池] 归还连接资源, 成功
[连接池] 申请连接资源, 开始
[连接池] 申请连接资源, 成功
数据库连接池: 连接中...
[连接池] 归还连接资源, 成功
[连接池] 申请连接资源, 开始
[连接池] 申请连接资源, 成功
数据库连接池: 连接中...
[连接池] 归还连接资源, 成功
--- PASS: TestPoolWithSize5 (0.00s)
PASS
*/
func TestPoolWithSize5(t *testing.T) {
conns := []conn{&dbConn{}, &dbConn{}, &dbConn{}, &httpConn{}, &wsConn{}}
p := NewPool(conns)
for i := 0; i < len(conns); i++ {
c, err := p.getConn()
require.NoError(t, err)
require.NotNil(t, c)
c.connect()
p.putConn(c)
}
}
11.1.2 pool.go
go
package _11pool
import (
"fmt"
)
// IPool 连接池
type IPool interface {
getConn() (conn, error)
putConn(conn)
}
// 连接池实现
type pool struct {
connDict map[conn]struct{}
}
func NewPool(conns []conn) IPool {
connDict := map[conn]struct{}{}
for _, c := range conns {
connDict[c] = struct{}{}
}
return &pool{
connDict: connDict,
}
}
// 获取连接
func (p *pool) getConn() (conn, error) {
fmt.Println("[连接池] 申请连接资源, 开始")
l := len(p.connDict)
if l == 0 {
return nil, fmt.Errorf("[连接池] 申请连接资源, 失败: 已无空闲连接资源")
}
fmt.Println("[连接池] 申请连接资源, 成功")
var c conn
for cIter := range p.connDict {
c = cIter
break
}
delete(p.connDict, c)
return c, nil
}
// 归还连接
func (p *pool) putConn(c conn) {
if c == nil {
return
}
p.connDict[c] = struct{}{}
fmt.Println("[连接池] 归还连接资源, 成功")
}
11.1.3 conn.go
go
package _11pool
import "fmt"
// 连接
type conn interface {
connect()
}
type dbConn struct{}
func (c *dbConn) connect() {
fmt.Println("数据库连接池: 连接中...")
}
type httpConn struct{}
func (c *httpConn) connect() {
fmt.Println("http连接池: 连接中...")
}
type wsConn struct{}
func (c *wsConn) connect() {
fmt.Println("http连接池: 连接中...")
}
11.2 chess_board
象棋棋盘
bash
11flyweight/112chess_board
├── chess.go
├── chess_test.go
└── readme.md
11.2.1 chess_test.go
go
package _12chess_board
import (
"github.com/stretchr/testify/require"
"testing"
)
/*
=== RUN TestChess
--- PASS: TestChess (0.00s)
PASS
*/
func TestChess(t *testing.T) {
board1 := NewChessBoard()
// board1.Move(1, 1, 2)
board2 := NewChessBoard()
// board2.Move(2, 2, 3)
require.EqualValues(t, board1.chessPieces[1].Unit, board2.chessPieces[1].Unit)
require.EqualValues(t, board1.chessPieces[2].Unit, board2.chessPieces[2].Unit)
}
11.2.2 chess.go
go
package _12chess_board
var ChessPieceUnits = map[int]*ChessPieceUnit{
1: {ID: 1, Name: "车", Color: "red"},
2: {ID: 2, Name: "马", Color: "yellow"},
3: {ID: 3, Name: "炮", Color: "blue"},
}
// ChessPiece 棋子
type ChessPiece struct {
Unit *ChessPieceUnit
X int
Y int
}
// ChessPieceUnit 棋子享元
type ChessPieceUnit struct {
ID int
Name string
Color string
}
// NewChessPieceUnit 创建棋子
func NewChessPieceUnit(id int) *ChessPieceUnit {
return ChessPieceUnits[id]
}
// ChessBoard 棋盘
type ChessBoard struct {
chessPieces map[int]*ChessPiece
}
func NewChessBoard() *ChessBoard {
board := &ChessBoard{chessPieces: map[int]*ChessPiece{}}
for id := range ChessPieceUnits {
board.chessPieces[id] = &ChessPiece{
Unit: NewChessPieceUnit(id),
X: 0,
Y: 0,
}
}
return board
}
// Move 移动棋子
func (c *ChessBoard) Move(id, x, y int) {
c.chessPieces[id].X = x
c.chessPieces[id].Y = y
}