【设计模式】11、flyweight 享元模式

文章目录

  • 十一、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 网络连接池, 都是应用场景

参考: 共享单车示例

https://www.bilibili.com/video/BV1Ka4y1L7jg/?spm_id_from=333.337.search-card.all.click\&vd_source=5dfe92471f5072eaffbf480e25acd82d

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
}
相关推荐
小bo波3 小时前
枚举实战
java·设计模式·枚举·后端开发·代码重构
不好听6137 小时前
Prompt 驱动 NLP:用大语言模型重新定义自然语言处理开发范式
设计模式·node.js·nlp
天文家9 小时前
深入理解装饰器与适配器:从设计模式到 Spring AOP 的工程实践
java·设计模式
workflower10 小时前
医院核心竞争力的四大重构
人工智能·安全·设计模式·重构·动态规划·scrum
折哥的程序人生 · 物流技术专研15 小时前
【电商多平台电子面单对接实战|第二篇】抖音代发电子面单对接:从“面条代码”到整洁架构的涅槃之路
设计模式·架构·系统架构·单元测试·代码规范·单一职责原则
葫芦和十三16 小时前
范式之变|Agent 设计,换语言了
人工智能·设计模式
ourenjiang16 小时前
【学习设计模式】原型模式
学习·设计模式·原型模式
贵慜_Derek16 小时前
《从零实现 Agent 系统》连载 20|MCP 与 Code Execution:协议、档位与 Sidecar
人工智能·设计模式·架构
Sam_Deep_Thinking2 天前
结算分摊的策略模式:不同营销活动的扣点计算方案
java·设计模式·架构·系统架构
故渊at2 天前
系列一:架构思想进阶 | 第3篇 SOLID 原则与设计模式实战:从“代码搬运工”到“架构师”的必经之路
观察者模式·设计模式·重构·架构·代理模式