【设计模式】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
}
相关推荐
小江的记录本8 小时前
【系统设计】《2026高频经典系统设计题》(秒杀系统、短链接系统、订单系统、支付系统、IM系统、RAG系统设计)(完整版)
java·后端·python·安全·设计模式·架构·系统架构
楼田莉子10 小时前
同步/异步日志系统:日志器管理器模块\全局接口\性能测试
linux·服务器·开发语言·c++·后端·设计模式
Meya112712 小时前
U位资产管理系统:数据中心“最后一公里“的精细化治理
设计模式·开源·交互
回忆2012初秋1 天前
工厂方法模式完整实现:GPS转换
设计模式·工厂方法模式
胡志辉的博客1 天前
多智能体协作,不是多开几个 Agent:从中介者模式看 OpenClaw 和 Hermes Agent
人工智能·设计模式·ai·agent·中介者模式·openclaw·herman
shark22222221 天前
能懂!基于Springboot的用户增删查改(三层设计模式)
spring boot·后端·设计模式
014-code1 天前
日志规范:怎么写才不算写废话
java·开发语言·设计模式·日志
楼田莉子1 天前
同步/异步日志系统:日志落地模块\日志器模块\异步日志模块
linux·服务器·c++·学习·设计模式
kyriewen112 天前
代码写成一锅粥?这5种设计模式让你的项目“起死回生”
前端·javascript·设计模式·typescript·ecmascript·html5
kyriewen2 天前
代码写成一锅粥?这5种设计模式让你的项目“起死回生”
前端·javascript·设计模式