creational/object-pool: reimplement the object pool pattern

This commit is contained in:
Tamer Tas 2016-10-19 18:36:35 +03:00
parent cf0e410960
commit 6a717fe88c
5 changed files with 50 additions and 115 deletions

View File

@ -18,7 +18,7 @@ A curated collection of idiomatic design & application patterns for Go language.
| [Abstract Factory](/creational/abstract_factory.md) | Provides an interface for creating families of releated objects | ✘ |
| [Builder](/creational/builder.md) | Builds a complex object using simple objects | ✘ |
| [Factory Method](/creational/factory.md) | Defers instantiation of an object to a specialized function for creating instances | ✘ |
| [Object Pool](/creational/object_pool.md) | Instantiates and maintains a group of objects instances of the same type | ✔ |
| [Object Pool](/creational/object-pool.md) | Instantiates and maintains a group of objects instances of the same type | ✔ |
| [Singleton](/creational/singleton.md) | Restricts instantiation of a type to one object | ✔ |
## Structural Patterns

View File

@ -5,7 +5,7 @@
* [Abstract Factory](/creational/abstract_factory.md)
* [Builder](/creational/builder.md)
* [Factory Method](/creational/factory.md)
* [Object Pool](/creational/object_pool.md)
* [Object Pool](/creational/object-pool.md)
* [Singleton](/creational/singleton.md)
* [Structural Patterns](/README.md#structural-patterns)
* [Adapter](/structural/adapter.md)

48
creational/object-pool.md Normal file
View File

@ -0,0 +1,48 @@
# Object Pool Pattern
The object pool creational design pattern is used to prepare and keep multiple
instances according to the demand expectation.
## Implementation
```go
package pool
type Pool chan *Object
func New(total int) *Pool {
p := make(chan *Object, total)
for i := 0; i < total; i++ {
p <- new(Object)
}
return p
}
```
## Usage
Given below is a simple lifecycle example on an object pool.
```go
p := pool.New(2)
select {
case obj := <-p:
obj.Do( /*...*/ )
p <- obj
default:
// No more objects left retry later or fail
return
}
```
## Rules of Thumb
- Object pool pattern is useful in cases where object initialization is more
expensive than the object maintenance.
- If there are spikes in demand as opposed to a steady demand, the maintenance
overhead might overweigh the benefits of an object pool.
- It has positive effects on performance due to object being initialized beforehand.

View File

@ -1,106 +0,0 @@
package main
import (
"container/list"
"errors"
"log"
)
var (
ErrNoMoreObject = errors.New("no more object")
ErrNotEnoughPoolSpace = errors.New("not enough pool space")
)
type Object struct {
ID string
}
type Pool interface {
Borrow() (*Object, error)
Return(*Object) error
}
type Allocate func() (*Object, error)
type implementation struct {
Size int
Allocate Allocate
FreeList *list.List
}
func New(initSize int, alloc Allocate) (Pool, error) {
p := &implementation{
Size: initSize,
Allocate: alloc,
FreeList: list.New(),
}
for i := 0; i < initSize; i++ {
obj, err := p.Allocate()
if err != nil {
return nil, err
}
p.FreeList.PushFront(obj)
}
return p, nil
}
func (p *implementation) Borrow() (*Object, error) {
elem := p.FreeList.Front()
if elem == nil {
return nil, ErrNoMoreObject
}
obj := p.FreeList.Remove(elem)
o := obj.(*Object)
return o, nil
}
func (p *implementation) Return(ref *Object) error {
if p.FreeList.Len() == p.Size {
return ErrNotEnoughPoolSpace
}
p.FreeList.PushBack(ref)
return nil
}
func main() {
const poolSize = 3
p, _ := New(poolSize, func() (*Object, error) {
return &Object{}, nil
})
ob, err := p.Borrow()
if err != nil {
log.Fatal(err)
}
log.Printf("borrow a object from pool: %#v\n", *ob)
for i := 0; i < poolSize-1; i++ {
o, err := p.Borrow()
if err != nil {
log.Fatal(err)
}
log.Printf("borrow a object from pool: %#v\n", *o)
}
_, err = p.Borrow()
if err.Error() != ErrNoMoreObject.Error() {
log.Fatalf("expect: %v\n", ErrNoMoreObject)
}
p.Return(ob)
ob1, err := p.Borrow()
if err != nil {
log.Fatal(err)
}
if ob != ob1 {
log.Fatal("expect the same object")
}
}

View File

@ -1,7 +0,0 @@
# Object Pool Pattern
The [object pool design pattern](https://en.wikipedia.org/wiki/Object_pool_pattern) allows multiple instances to be kept in a collection ("pool") in order to have already been initialized when other instances are ready to use them.
# Implementation and Example
An example with implementation and usage can be found in [object_pool.go](object_pool.go).