mirror of
https://github.com/tmrts/go-patterns.git
synced 2024-11-24 05:56: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 | ✘ |
|
| [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 | ✘ |
|
| [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 | ✘ |
|
| [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 | ✔ |
|
| [Singleton](/creational/singleton.md) | Restricts instantiation of a type to one object | ✔ |
|
||||||
|
|
||||||
## Structural Patterns
|
## Structural Patterns
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* [Abstract Factory](/creational/abstract_factory.md)
|
* [Abstract Factory](/creational/abstract_factory.md)
|
||||||
* [Builder](/creational/builder.md)
|
* [Builder](/creational/builder.md)
|
||||||
* [Factory Method](/creational/factory.md)
|
* [Factory Method](/creational/factory.md)
|
||||||
* [Object Pool](/creational/object_pool.md)
|
* [Object Pool](/creational/object-pool.md)
|
||||||
* [Singleton](/creational/singleton.md)
|
* [Singleton](/creational/singleton.md)
|
||||||
* [Structural Patterns](/README.md#structural-patterns)
|
* [Structural Patterns](/README.md#structural-patterns)
|
||||||
* [Adapter](/structural/adapter.md)
|
* [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