I am studying design patterns in go. I need a review of this implementation. I started this exercise from wikipedia description of the pattern and implementing step by step all the sentences.
I decided to use two objects: the pool and the object managed by the pool.
type PoolObject struct {
id int
}
type Pool struct {
idle *list.List
active *list.List
}
When pool is initialized two empty lists were created.
func InitPool() Pool {
pool := &Pool{
list.New(),
list.New(),
}
return *pool
}
Any time an object is requested, it's returned from the idle list or created from scratch.
func (p *Pool) Loan() PoolObject {
if p.idle.Len() > 0 {
for e, i := p.idle.Front(), 0; e != nil; e, i = e.Next(), i+1 {
if i == 0 {
object := e.Value.(PoolObject)
return object
}
}
}
object := PoolObject{p.NumberOfObjectsInPool() + 1}
p.active.PushBack(object)
return object
}
Any time an object is returned, it's removed from the active list and pushed in the idle list.
func (p *Pool) Receive(object PoolObject) {
p.idle.PushBack(object)
for e, i := p.active.Front(), 0; e != nil; e, i = e.Next(), i+1 {
if object == e.Value.(PoolObject) {
p.active.Remove(e)
return
}
}
}
sync.Pool(typically with tiny type safe wrappers aroundPool.GetandPool.Putfor each specific pool type you use). \$\endgroup\$containerpackages are rarely used in real code. Only use alist.Listif you really need the properties of a doubly linked list, in the vast vast majority of cases a simple slice is much better and faster. In this case, you'd append items to an idle slice and pull off the tail end of it (i.e. use a slice as a LIFO queue; btw, a LIFO is preferable here vs FIFO both because it's easier to efficiently do the former with a slice and because recent objects are more likely to be in CPU/memory caches and should preferentially be reused first). \$\endgroup\$