From 6a717fe88c611a75258725d982bfd9a6acbe3d0e Mon Sep 17 00:00:00 2001 From: Tamer Tas Date: Wed, 19 Oct 2016 18:36:35 +0300 Subject: [PATCH] creational/object-pool: reimplement the object pool pattern --- README.md | 2 +- SUMMARY.md | 2 +- creational/object-pool.md | 48 +++++++++++++++++ creational/object_pool.go | 106 -------------------------------------- creational/object_pool.md | 7 --- 5 files changed, 50 insertions(+), 115 deletions(-) create mode 100644 creational/object-pool.md delete mode 100644 creational/object_pool.go delete mode 100644 creational/object_pool.md diff --git a/README.md b/README.md index 5b106b6..ee7457a 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/SUMMARY.md b/SUMMARY.md index 2436622..df351b3 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -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) diff --git a/creational/object-pool.md b/creational/object-pool.md new file mode 100644 index 0000000..37066d3 --- /dev/null +++ b/creational/object-pool.md @@ -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. diff --git a/creational/object_pool.go b/creational/object_pool.go deleted file mode 100644 index 28a582d..0000000 --- a/creational/object_pool.go +++ /dev/null @@ -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") - } -} diff --git a/creational/object_pool.md b/creational/object_pool.md deleted file mode 100644 index e2770e1..0000000 --- a/creational/object_pool.md +++ /dev/null @@ -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). \ No newline at end of file