这次介绍最后一个创建型模式——对象池模式。顾名思义,对象池模式就是预先初始化创建好多个对象,并将之保存在一个池子里。当需要的时候,客户端就可以从池子里申请一个对象使用,使用完以后再将之放回到池子里。池子里的对象在应用运行期间永远不会被破坏或回收。

适用场景:

  1. 当需要的对象的创建成本比较高,且该类型的对象在应用运行期间只需要有限的数量
  2. 对象是不可变的
  3. 性能原因:预创建的对象可以显著提升应用性能

我们在开发中最熟悉的对象池应该是数据库连接池了。因为网络因素,数据库连接池中的每个对象的创建成本都比较高,且应用在运行期间会需要多个数据库连接对象。另外,每个数据库的连接池中对象的属性都是一样的,且在运行期间这些对象的属性几乎通常都是不可变的。

来看个模拟的数据库连接对象池模型的例子。

iPoolObject.go

type iPoolObject interface {
//This is any id which can be used to compare two different pool objects
getID() string
}

connection.go

type connection struct {
id string
} func (c *connection) getID() string {
return c.id
}

pool.go

import (
"fmt"
"sync"
) type pool struct {
idle []iPoolObject
active []iPoolObject
capacity int
muLock *sync.Mutex
} //initPool Initialize the pool
func initPool(poolObjects []iPoolObject) (*pool, error) {
if len(poolObjects) == 0 {
return nil, fmt.Errorf("cannot craete a pool of 0 length")
}
active := make([]iPoolObject, 0)
pool := &pool{
idle: poolObjects,
active: active,
capacity: len(poolObjects),
muLock: new(sync.Mutex),
}
return pool, nil
} func (p *pool) loan() (iPoolObject, error) {
p.muLock.Lock()
defer p.muLock.Unlock()
if len(p.idle) == 0 {
return nil, fmt.Errorf("no pool object free. Please request after sometime")
}
obj := p.idle[0]
p.idle = p.idle[1:]
p.active = append(p.active, obj)
fmt.Printf("Loan Pool Object with ID: %s\n", obj.getID())
return obj, nil
} func (p *pool) receive(target iPoolObject) error {
p.muLock.Lock()
defer p.muLock.Unlock()
err := p.remove(target)
if err != nil {
return err
}
p.idle = append(p.idle, target)
fmt.Printf("Return Pool Object with ID: %s\n", target.getID())
return nil
} func (p *pool) remove(target iPoolObject) error {
currentActiveLength := len(p.active)
for i, obj := range p.active {
if obj.getID() == target.getID() {
p.active[currentActiveLength-1], p.active[i] = p.active[i], p.active[currentActiveLength-1]
p.active = p.active[:currentActiveLength-1]
return nil
}
}
return fmt.Errorf("targe pool object doesn't belong to the pool")
}

main.go

import (
"log"
"strconv"
) func main() {
connections := make([]iPoolObject, 0)
for i := 0; i < 3; i++ {
c := &connection{id: strconv.Itoa(i)}
connections = append(connections, c)
}
pool, err := initPool(connections)
if err != nil {
log.Fatalf("Init Pool Error: %s", err)
}
conn1, err := pool.loan()
if err != nil {
log.Fatalf("Pool Loan Error: %s", err)
}
conn2, err := pool.loan()
if err != nil {
log.Fatalf("Pool Loan Error: %s", err)
}
_ = pool.receive(conn1)
_ = pool.receive(conn2)
}

输出内容为:

Loan Pool Object with ID: 0
Loan Pool Object with ID: 1
Return Pool Object with ID: 0
Return Pool Object with ID: 1

代码已上传至GitHub:zhyea / go-patterns / object-pool-pattern

END!

GoLang设计模式06 - 对象池模式的更多相关文章

  1. 游戏开发设计模式之对象池模式(unity3d 示例实现)

    前篇:游戏开发设计模式之命令模式(unity3d 示例实现) 博主才学尚浅,难免会有错误,尤其是设计模式这种极富禅意且需要大量经验的东西,如果哪里书写错误或有遗漏,还请各位前辈指正. 原理:从一个固定 ...

  2. java设计模式之实现对象池模式示例分享

    http://www.jb51.net/article/46941.htm 对象池模式经常用在频繁创建.销毁对象,且对象创建.销毁开销很大的场景,比如数据库连接池.线程池.任务队列池等.本代码简单,没 ...

  3. 对象池模式(Object Pool Pattern)

    本文节选自<设计模式就该这样学> 1 对象池模式的定义 对象池模式(Object Pool Pattern),是创建型设计模式的一种,将对象预先创建并初始化后放入对象池中,对象提供者就能利 ...

  4. C++设计模式 之 “对象性能” 模式:Singleton、Flyweight

    “对象性能”模式 面向对象很好地解决了“抽象”的问题,但是必不可免地要付出一定的代价.对于通常情况来讲,面向对象的成本大都可以忽略不计.但是某些情况,面向对象所带来的成本必须谨慎处理. 典型模式 # ...

  5. C++设计模式 之 “对象创建”模式:Factory Method、Abstract Factory、Prototype、Builder

    part 0 “对象创建”模式 通过“对象创建” 模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定.它是接口抽象之后的第一步工作. 典型模式 Fact ...

  6. GoLang设计模式3 - 抽象工厂模式

    之前我们介绍了工厂设计模式,现在我们再看一下抽象工厂设计模式.抽象工程模式顾名思义就是对工厂模式的一层抽象,也是创建型模式的一种,通常用来创建一组存在相关性的对象. UML类图大致如下: 类图比较复杂 ...

  7. GoLang设计模式07 - 责任链模式

    责任链模式是一种行为型设计模式.在这种模式中,会为请求创建一条由多个Handler组成的链路.每一个进入的请求,都会经过这条链路.这条链路上的Handler可以选择如下操作: 处理请求或跳过处理 决定 ...

  8. php设计模式 数据对象映射模式

    数据对象映射模式,是将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作. 在代码中实现数据对象映射模式,实现一个ORM类,将复杂的sql语句映射成对象属性的操作.对象关系映射(Obje ...

  9. 游戏设计模式——Unity对象池

    对象池这个名字听起来很玄乎,其实就是将一系列需要反复创建和销毁的对象存储在一个看不到的地方,下次用同样的东西时往这里取,类似于一个存放备用物质的仓库. 它的好处就是避免了反复实例化个体的运算,能减少大 ...

随机推荐

  1. shell常识

    1 #!/bin/bash 2 : << ! 3 #使用变量 4 your_name="qinjx" 5 echo $your_name 6 echo ${your_n ...

  2. Java基础技术基础面试【笔记】

    Java基础技术基础面试[笔记] String.StringBuilder以及StringBuffer三者之间的区别? 三者的区别可以从可变性,线程安全性,性能这三个部分进行说明 可变性 从可变性来说 ...

  3. SpringBoot开发十六-帖子详情

    需求介绍 实现帖子详情,在帖子标题上增加访问详情页面的链接. 代码实现 开发流程: 首先在数据访问层新增一个方法 实现查看帖子的方法 业务层同理增加查询方法 最后在表现层处理查询请求 数据访问层增加根 ...

  4. Echarts 展示两条动态数据曲线

    利用Echarts 展示两条动态数据曲线,每1秒刷新一下数据,在echart官网例子基础上修改,修改了仿真数据的生成方式.生成数量,曲线数量,最总效果图如下: 详细代码如下: 遇到的主要问题点, 1, ...

  5. DVWA(三):SQL injection 全等级SQL注入

    (本文不定期更新) 一.所需环境: 1.DVWA 2.web环境 phpstudy/wamp 3.burp suite 二.SQL注入产生的原因: 程序员在编写代码的时候,没有对用户输入数据的合法性进 ...

  6. C#10在List, Queue 以及Stack中使用EnsureCapacity方法来提升性能

    简介 在今天的文章中,我们将介绍 C# 10 中引入的一项新功能.这是已添加到 List.Queue 和 Stack 集合中的 EnsureCapacity 方法.我们将讨论为什么我们应该使用这个方法 ...

  7. sentinel使用(结合gateway)

    前 如果你想在Spring Cloud Gateway中使用Sentinel Starter,你需要添加Spring - Cloud -alibaba- Sentinel - Gateway依赖,并添 ...

  8. C++CLR类库封装Native类库并用C#调用 - 草稿

    1.创建Native类库 新建项目->其他语言->Visual C++->Win32控制台应用程序->DLL     添加头文件       添加源文件       选择生成路 ...

  9. mysql开启远程访问权限的设置

    MySql-Server 出于安全方面考虑默认只允许本机(localhost, 127.0.0.1)来连接访问. 所以必须给root修改可以远程访问的权限 1.在连接服务器后,操作mysql系统数据库 ...

  10. 深入浅出Mybatis系列(十)---延迟加载

    一.延迟加载 resultMap可以实现高级映射(使用association.collection实现一对一及一对多映射),association.collection具备延迟加载功能. 延迟加载:先 ...