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

适用场景:

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

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

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

iPoolObject.go

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

connection.go

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

pool.go

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

main.go

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

输出内容为:

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

代码已上传至GitHub:zhyea / go-patterns / object-pool-pattern

END!

 


仅是学习笔记,难免出错,望不吝指点

 
转 https://www.cnblogs.com/amunote/p/15259628.html

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

适用场景:

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

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

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

iPoolObject.go

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

connection.go

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

pool.go

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

main.go

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

输出内容为:

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

代码已上传至GitHub:zhyea / go-patterns / object-pool-pattern

END!