GoLang设计模式07 - 对象池模式

这次介绍最后一个创建型模式——对象池模式。顾名思义,对象池模式就是预先初始化创建好多个对象,并将之保存在一个池子里。当需要的时候,客户端就可以从池子里申请一个对象使用,使用完以后再将之放回到池子里。池子里的对象在应用运行期间永远不会被破坏或回收。

适用场景:

  1. 当需要的对象的创建成本比较高,且该类型的对象在应用运行期间只需要有限的数量
  2. 对象是不可变的
  3. 性能原因:预创建的对象可以显著提升应用性能

我们在开发中最熟悉的对象池应该是数据库连接池了。因为网络因素,数据库连接池中的每个对象的创建成本都比较高,且应用在运行期间会需要多个数据库连接对象。另外,每个数据库的连接池中对象的属性都是一样的,且在运行期间这些对象的属性几乎通常都是不可变的。

来看个模拟的数据库连接对象池模型的例子。

iPoolObject.go

1 type iPoolObject interface {
2     //This is any id which can be used to compare two different pool objects
3     getID() string
4 }

connection.go

1 type connection struct {
2     id string
3 }
4  
5 func (c *connection) getID() string {
6     return c.id
7 }

pool.go

 1 import (
 2     "fmt"
 3     "sync"
 4 )
 5  
 6 type pool struct {
 7     idle     []iPoolObject
 8     active   []iPoolObject
 9     capacity int
10     muLock   *sync.Mutex
11 }
12  
13 //initPool Initialize the pool
14 func initPool(poolObjects []iPoolObject) (*pool, error) {
15     if len(poolObjects) == 0 {
16         return nil, fmt.Errorf("cannot craete a pool of 0 length")
17     }
18     active := make([]iPoolObject, 0)
19     pool := &pool{
20         idle:     poolObjects,
21         active:   active,
22         capacity: len(poolObjects),
23         muLock:   new(sync.Mutex),
24     }
25     return pool, nil
26 }
27  
28 func (p *pool) loan() (iPoolObject, error) {
29     p.muLock.Lock()
30     defer p.muLock.Unlock()
31     if len(p.idle) == 0 {
32         return nil, fmt.Errorf("no pool object free. Please request after sometime")
33     }
34     obj := p.idle[0]
35     p.idle = p.idle[1:]
36     p.active = append(p.active, obj)
37     fmt.Printf("Loan Pool Object with ID: %s\n", obj.getID())
38     return obj, nil
39 }
40  
41 func (p *pool) receive(target iPoolObject) error {
42     p.muLock.Lock()
43     defer p.muLock.Unlock()
44     err := p.remove(target)
45     if err != nil {
46         return err
47     }
48     p.idle = append(p.idle, target)
49     fmt.Printf("Return Pool Object with ID: %s\n", target.getID())
50     return nil
51 }
52  
53 func (p *pool) remove(target iPoolObject) error {
54     currentActiveLength := len(p.active)
55     for i, obj := range p.active {
56         if obj.getID() == target.getID() {
57             p.active[currentActiveLength-1], p.active[i] = p.active[i], p.active[currentActiveLength-1]
58             p.active = p.active[:currentActiveLength-1]
59             return nil
60         }
61     }
62     return fmt.Errorf("targe pool object doesn't belong to the pool")
63 }

main.go

 1 import (
 2     "log"
 3     "strconv"
 4 )
 5  
 6 func main() {
 7     connections := make([]iPoolObject, 0)
 8     for i := 0; i < 3; i++ {
 9         c := &connection{id: strconv.Itoa(i)}
10         connections = append(connections, c)
11     }
12     pool, err := initPool(connections)
13     if err != nil {
14         log.Fatalf("Init Pool Error: %s", err)
15     }
16     conn1, err := pool.loan()
17     if err != nil {
18         log.Fatalf("Pool Loan Error: %s", err)
19     }
20     conn2, err := pool.loan()
21     if err != nil {
22         log.Fatalf("Pool Loan Error: %s", err)
23     }
24     _ = pool.receive(conn1)
25     _ = pool.receive(conn2)
26 }

输出内容为:

1 Loan Pool Object with ID: 0
2 Loan Pool Object with ID: 1
3 Return Pool Object with ID: 0
4 Return Pool Object with ID: 1

 

posted @ 2023-04-20 18:43  格局打得开  阅读(152)  评论(0)    收藏  举报