mirror of
https://github.com/tmrts/go-patterns.git
synced 2024-11-23 21:46:08 +03:00
creational/object-pool: reimplement the object pool pattern
This commit is contained in:
parent
cf0e410960
commit
6a717fe88c
@ -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
|
||||
|
@ -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
48
creational/object-pool.md
Normal 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.
|
@ -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")
|
||||
}
|
||||
}
|
@ -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).
|
Loading…
Reference in New Issue
Block a user