【设计模式】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
}
相关推荐
bandaoyu1 小时前
【设计模式】装饰器模式(Decorator Pattern)
设计模式·装饰器模式
lijiachang0307182 小时前
设计模式(一):单例模式
c++·笔记·学习·程序人生·单例模式·设计模式·大学生
抓哇FullStack-Junior3 小时前
设计模式——适配器模式
java·设计模式·适配器模式
silver6874 小时前
桥接模式详解
设计模式
思忖小下5 小时前
梳理你的思路(从OOP到架构设计)_设计模式Observer模式
观察者模式·设计模式·eit
ThetaarSofVenice7 小时前
能省一点是一点 - 享元模式(Flyweight Pattern)
java·设计模式·享元模式
记得多喝水o7 小时前
图解设计模式
设计模式
InSighT__7 小时前
设计模式与游戏完美开发(2)
java·游戏·设计模式
思忖小下8 小时前
梳理你的思路(从OOP到架构设计)_设计模式Android + Composite模式
设计模式·composite模式
silver6878 小时前
单例模式详解
设计模式