GoLang设计模式07 - 对象池模式
这次介绍最后一个创建型模式——对象池模式。顾名思义,对象池模式就是预先初始化创建好多个对象,并将之保存在一个池子里。当需要的时候,客户端就可以从池子里申请一个对象使用,使用完以后再将之放回到池子里。池子里的对象在应用运行期间永远不会被破坏或回收。
适用场景:
- 当需要的对象的创建成本比较高,且该类型的对象在应用运行期间只需要有限的数量
- 对象是不可变的
- 性能原因:预创建的对象可以显著提升应用性能
我们在开发中最熟悉的对象池应该是数据库连接池了。因为网络因素,数据库连接池中的每个对象的创建成本都比较高,且应用在运行期间会需要多个数据库连接对象。另外,每个数据库的连接池中对象的属性都是一样的,且在运行期间这些对象的属性几乎通常都是不可变的。
来看个模拟的数据库连接对象池模型的例子。
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
浙公网安备 33010602011771号