mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-09-29 22:56:42 +08:00
523 lines
29 KiB
HTML
523 lines
29 KiB
HTML
<!DOCTYPE html>
|
||
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
|
||
<link rel="icon" href="/static/favicon.png">
|
||
<title>23 深入解读对象池技术:共享让生活更便捷.md.html</title>
|
||
<!-- Spectre.css framework -->
|
||
<link rel="stylesheet" href="/static/index.css">
|
||
<!-- theme css & js -->
|
||
<meta name="generator" content="Hexo 4.2.0">
|
||
</head>
|
||
<body>
|
||
<div class="book-container">
|
||
<div class="book-sidebar">
|
||
<div class="book-brand">
|
||
<a href="/">
|
||
<img src="/static/favicon.png">
|
||
<span>技术文章摘抄</span>
|
||
</a>
|
||
</div>
|
||
<div class="book-menu uncollapsible">
|
||
<ul class="uncollapsible">
|
||
<li><a href="/" class="current-tab">首页</a></li>
|
||
</ul>
|
||
<ul class="uncollapsible">
|
||
<li><a href="../">上一级</a></li>
|
||
</ul>
|
||
<ul class="uncollapsible">
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/00 生活中的设计模式:启程之前,请不要错过我.md.html">00 生活中的设计模式:启程之前,请不要错过我</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/01 监听模式:坑爹的热水器.md.html">01 监听模式:坑爹的热水器</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/02 适配模式:身高不够鞋来凑.md.html">02 适配模式:身高不够鞋来凑</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/03 状态模式:人与水的三态.md.html">03 状态模式:人与水的三态</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/04 单例模式:你是我生命的唯一.md.html">04 单例模式:你是我生命的唯一</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/05 职责模式:我的假条去哪了.md.html">05 职责模式:我的假条去哪了</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/06 中介模式:找房子问中介.md.html">06 中介模式:找房子问中介</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/07 代理模式:帮我拿一下快递.md.html">07 代理模式:帮我拿一下快递</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/08 装饰模式:你想怎么穿就怎么穿.md.html">08 装饰模式:你想怎么穿就怎么穿</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/09 工厂模式:你要拿铁还是摩卡.md.html">09 工厂模式:你要拿铁还是摩卡</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/10 迭代模式:下一个就是你了.md.html">10 迭代模式:下一个就是你了</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/11 组合模式:自己组装电脑.md.html">11 组合模式:自己组装电脑</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/12 构建模式:想要车还是庄园.md.html">12 构建模式:想要车还是庄园</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/13 克隆模式:给你一个分身术.md.html">13 克隆模式:给你一个分身术</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/14 策略模式:怎么来不重要,人到就行.md.html">14 策略模式:怎么来不重要,人到就行</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/15 命令模式:大闸蟹,走起!.md.html">15 命令模式:大闸蟹,走起!</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/16 备忘模式:好记性不如烂笔头.md.html">16 备忘模式:好记性不如烂笔头</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/17 享元模式:颜料很贵必须充分利用.md.html">17 享元模式:颜料很贵必须充分利用</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/18 外观模式:学妹别慌,学长帮你.md.html">18 外观模式:学妹别慌,学长帮你</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/19 访问模式:一千个读者一千个哈姆雷特.md.html">19 访问模式:一千个读者一千个哈姆雷特</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/20 生活中的设计模式:与经典设计模式的不解渊源.md.html">20 生活中的设计模式:与经典设计模式的不解渊源</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/21 生活中的设计模式:那些未完待续的设计模式.md.html">21 生活中的设计模式:那些未完待续的设计模式</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/22 深入解读过滤器模式:制作一杯鲜纯细腻的豆浆.md.html">22 深入解读过滤器模式:制作一杯鲜纯细腻的豆浆</a>
|
||
</li>
|
||
<li>
|
||
<a class="current-tab" href="/专栏/白话设计模式 28 讲(完)/23 深入解读对象池技术:共享让生活更便捷.md.html">23 深入解读对象池技术:共享让生活更便捷</a>
|
||
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/24 深入解读回调机制:把你技能亮出来.md.html">24 深入解读回调机制:把你技能亮出来</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/25 谈谈我对设计模式的理解.md.html">25 谈谈我对设计模式的理解</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/26 谈谈我对设计原则的思考.md.html">26 谈谈我对设计原则的思考</a>
|
||
</li>
|
||
<li>
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/27 谈谈我对项目重构的看法.md.html">27 谈谈我对项目重构的看法</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
|
||
<div class="sidebar-toggle-inner"></div>
|
||
</div>
|
||
<script>
|
||
function add_inner() {
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
inner.classList.add('show')
|
||
}
|
||
function remove_inner() {
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
inner.classList.remove('show')
|
||
}
|
||
function sidebar_toggle() {
|
||
let sidebar_toggle = document.querySelector('.sidebar-toggle')
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
let content = document.querySelector('.off-canvas-content')
|
||
if (sidebar_toggle.classList.contains('extend')) { // show
|
||
sidebar_toggle.classList.remove('extend')
|
||
sidebar.classList.remove('hide')
|
||
content.classList.remove('extend')
|
||
} else { // hide
|
||
sidebar_toggle.classList.add('extend')
|
||
sidebar.classList.add('hide')
|
||
content.classList.add('extend')
|
||
}
|
||
}
|
||
function open_sidebar() {
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
sidebar.classList.add('show')
|
||
overlay.classList.add('show')
|
||
}
|
||
function hide_canvas() {
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
sidebar.classList.remove('show')
|
||
overlay.classList.remove('show')
|
||
}
|
||
</script>
|
||
<div class="off-canvas-content">
|
||
<div class="columns">
|
||
<div class="column col-12 col-lg-12">
|
||
<div class="book-navbar">
|
||
<!-- For Responsive Layout -->
|
||
<header class="navbar">
|
||
<section class="navbar-section">
|
||
<a onclick="open_sidebar()">
|
||
<i class="icon icon-menu"></i>
|
||
</a>
|
||
</section>
|
||
</header>
|
||
</div>
|
||
<div class="book-content" style="max-width: 960px; margin: 0 auto;
|
||
overflow-x: auto;
|
||
overflow-y: hidden;">
|
||
<div class="book-post">
|
||
<p id="tip" align="center"></p>
|
||
<div><h1>23 深入解读对象池技术:共享让生活更便捷</h1>
|
||
<p>【故事剧情】</p>
|
||
<blockquote>
|
||
<p>大学的室友兼死党 Sam 首次来杭州,作为东道主的 Tony 自然得悉心招待,不敢怠慢。这不,不仅要陪吃陪喝还得陪玩,哈哈!</p>
|
||
<p>第一次来杭州,西湖必然是非去不可的。正值周末,风和日丽,最适合游玩。上午 9 点出发,Tony 和 Sam 打一辆滴滴快车从滨江到西湖的南山路,然后从大华饭店步行到断桥,之后是穿越断桥,漫步白堤,游走孤山岛,就这样一路走走停停,闲聊、拍照,很快就到了中午。中午在岳王庙附近找了一家生煎,简单解决午餐(大餐留着晚上吃)。因为拍照拍的比较多,手机没电了,正好看到店里有共享充电宝,便借了一个给手机充满电,也多休息了一个小时。 下午,他们准备骑行最美西湖路;吃完饭,找了两辆共享自行车,从杨公堤开始骑行,路过太子湾、雷峰塔,然后再到柳浪闻莺。之后就是沿湖步行走到龙翔桥,找了一家最具杭州特色的饭店解决晚餐……</p>
|
||
<p>这一路行程他们从共享汽车(滴滴快车)到共享自行车,再到共享充电宝,共享的生活方式已如影随形地渗透到了生活的方方面面。<strong>共享,不仅让我们出行更便捷,而且资源更节约!</strong></p>
|
||
</blockquote>
|
||
<p><img src="assets/9ba61de0-9608-11e8-9f67-05ec09da262a.jpg" alt="img" /></p>
|
||
<h3>用程序来模拟生活</h3>
|
||
<p>共享经济的飞速发展真的是改变了我们的生活方式,共享自行车、共享雨伞、共享充电宝、共享 KTV 等,共享让我们的生活更便利,你可以不用带充电宝,却可以随时用到它;共享让我们的资源更节约,你可以不用买自行车,但每个人都能骑到自行车(一辆车可以为多个人服务)。我们以共享充电宝为例,用程序来模拟一下它是怎样做到资源节约和共享的。</p>
|
||
<p>源码示例:</p>
|
||
<pre><code class="language-python">class PowerBank:
|
||
"移动电源"
|
||
def __init__(self, serialNum, electricQuantity):
|
||
self.__serialNum = serialNum
|
||
self.__electricQuantity = electricQuantity
|
||
self.__user = ''
|
||
def getSerialNum(self):
|
||
return self.__serialNum
|
||
def getElectricQuantity(self):
|
||
return self.__electricQuantity
|
||
def setUser(self, user):
|
||
self.__user = user
|
||
def getUser(self):
|
||
return self.__user
|
||
def showInfo(self):
|
||
print("序列号:" + str(self.__serialNum) + " 电量:" + str(self.__electricQuantity) + "% 使用者:" + self.__user)
|
||
class ObjectPack:
|
||
"对象的包装类,封装指定的对象(如充电宝)是否被使用中"
|
||
def __init__(self, obj, inUsing = False):
|
||
self.__obj = obj
|
||
self.__inUsing = inUsing
|
||
def inUsing(self):
|
||
return self.__inUsing
|
||
def setUsing(self, isUsing):
|
||
self.__inUsing = isUsing
|
||
def getObj(self):
|
||
return self.__obj
|
||
class PowerBankBox:
|
||
"存放移动电源的智能箱盒"
|
||
def __init__(self):
|
||
self.__pools = {}
|
||
self.__pools['0001'] = ObjectPack(PowerBank('0001', 100))
|
||
self.__pools['0002'] = ObjectPack(PowerBank('0002', 100))
|
||
def borrow(self, serialNum):
|
||
"使用移动电源"
|
||
item = self.__pools.get(serialNum)
|
||
result = None
|
||
if(item is None):
|
||
print("没有可用的电源!")
|
||
elif(not item.inUsing()):
|
||
item.setUsing(True)
|
||
result = item.getObj()
|
||
else:
|
||
print(str(serialNum) + "电源已被借用!")
|
||
return result
|
||
def giveBack(self, serialNum):
|
||
"归还移动电源"
|
||
item = self.__pools.get(serialNum)
|
||
if(item is not None):
|
||
item.setUsing(False)
|
||
print(str(serialNum) + "电源已归还!")
|
||
</code></pre>
|
||
<p>测试代码:</p>
|
||
<pre><code class="language-python">def testPowerBank():
|
||
box = PowerBankBox()
|
||
powerBank1 = box.borrow('0001')
|
||
if(powerBank1 is not None):
|
||
powerBank1.setUser('Tony')
|
||
powerBank1.showInfo()
|
||
powerBank2 = box.borrow('0002')
|
||
if(powerBank2 is not None):
|
||
powerBank2.setUser('Sam')
|
||
powerBank2.showInfo()
|
||
powerBank3 = box.borrow('0001')
|
||
box.giveBack('0001')
|
||
powerBank3 = box.borrow('0001')
|
||
if(powerBank3 is not None):
|
||
powerBank3.setUser('Aimee')
|
||
powerBank3.showInfo()
|
||
</code></pre>
|
||
<p>输出结果:</p>
|
||
<pre><code>序列号:0001 电量:100% 使用者:Tony
|
||
序列号:0002 电量:100% 使用者:Sam
|
||
0001电源已被借用!
|
||
0001电源已归还!
|
||
序列号:0001 电量:100% 使用者:Aimee
|
||
</code></pre>
|
||
<h3>从剧情中思考对象池机制</h3>
|
||
<p>在共享充电宝这个示例中,如果还有未被借用的设备,我们就能借到充电宝给自己的手机充电;用完之后把充电宝还回去,继续让下一个人借用,这样就能让充电宝的利用率达到最大。如共享充电宝一样,在程序中也有一种对应的机制,可以让对象重复地被使用,这就是<strong>对象池</strong>。</p>
|
||
<h4>对象池</h4>
|
||
<blockquote>
|
||
<p><strong>对象池</strong>其实就是一个集合,里面包含了我们需要的已经过初始化且可以使用的对象,我们称这些对象都被池化了,也就是被对象池所管理,想要这样的对象,从池子里取一个就行,但是用完得归还。</p>
|
||
</blockquote>
|
||
<p>可以理解对象池为单例模式的延展,多例模式,就那么几个对象实例,再多没有了;要用可以,但用完必须归还,这样其他人才能再使用。可以用下面一张图来形象的表示:</p>
|
||
<p><img src="assets/32028c60-9609-11e8-bd60-15398afc36e1.jpg" alt="img" /></p>
|
||
<p>上面共享充电定的示例就能非常形象地类比对象池的概念:对象池就如同存放充电宝的智能箱盒,对象就量充电定,而对象的借用、使用、归还分别对应充电宝的借用、使用、归还。</p>
|
||
<h4>与享元模式的联系</h4>
|
||
<p>在《[第17课:生活中的享元模式——颜料很贵必须充分利用]》这一篇文章中我们知道享元模式可以实现对象的共享,通过使用享元模式可以节约内存空间,提高系统的性能。但这个模式也存在一个问题,那就是享元对象的内部状态和属性,一经创建后不会被随意改变。因为如果可以改变,则 A 取得这个对象 obj 后,改变了其状态;B 再去取这个对象 obj 时就已经不是原来的状态了。</p>
|
||
<p>对象池机制正好可以解决享元模式的这个缺陷。它通过借、还的机制,让一个对象在某段时间内被一个使用者独占,用完之后归还该对象,在独占的这段时间内使用者可以修改对象的部分属性(因为这段时间内其他用户不会使用这个对象);而享元模式因为没有这种机制,享元对象在整个生命周期都是被所有使用者共享的。</p>
|
||
<blockquote>
|
||
<p>什么就<strong>独占</strong>?就是你用着这个充电宝,(同一时刻)别人就不能用了,因为只有一个接口,只能给一个手机充电。</p>
|
||
<p>什么叫<strong>共享</strong>?就是深夜中几个人围一圆桌坐着,头顶上挂着一盏电灯,大家都享受着这盏灯带来的光明,这盏电灯就是共享的。而且一定范围内来讲它是无限共享的,因为圆桌上坐着 5 个人和坐着 10 个人,他们感觉到的光亮是一样的。</p>
|
||
</blockquote>
|
||
<p>对象池机制是享元模式的一个延伸,可以理解为享元模式的升级版。</p>
|
||
<h3>对象池机制的模型抽象</h3>
|
||
<h4>代码框架</h4>
|
||
<p>池子、借用、归还是对象池机制的核心思想,我们可以基于这一思想逐步抽象出一个简单可用的实现模型。</p>
|
||
<pre><code class="language-python">from abc import ABCMeta, abstractmethod
|
||
# 引入ABCMeta和abstractmethod来定义抽象类和抽象方法
|
||
import logging
|
||
# 引入logging模块用于输出日志信息
|
||
import time
|
||
# 引入时间模块
|
||
class PooledObject:
|
||
"池对象,也称池化对象"
|
||
def __init__(self, obj):
|
||
self.__obj = obj
|
||
self.__busy = False
|
||
def getObject(self):
|
||
return self.__obj
|
||
def setObject(self, obj):
|
||
self.__obj = obj
|
||
def isBusy(self):
|
||
return self.__busy
|
||
def setBusy(self, busy):
|
||
self.__busy = busy
|
||
class ObjectPool(metaclass=ABCMeta):
|
||
"对象池"
|
||
"对象池初始化大小"
|
||
InitialNumOfObjects = 10
|
||
"对象池最大的大小"
|
||
MaxNumOfObjects = 50
|
||
def __init__(self):
|
||
self.__pools = []
|
||
for i in range(0, ObjectPool.InitialNumOfObjects):
|
||
obj = self.createPooledObject()
|
||
self.__pools.append(obj)
|
||
@abstractmethod
|
||
def createPooledObject(self):
|
||
"子类提供创建对象的方法"
|
||
pass
|
||
def borrowObject(self):
|
||
# 如果找到空闲对象,直接返回
|
||
obj = self._findFreeObject()
|
||
if(obj is not None):
|
||
logging.info("%s对象已被借用, time:%d", id(obj), time.time())
|
||
return obj
|
||
# 如果对象池未满,则添加新的对象
|
||
if(len(self.__pools) < ObjectPool.MaxNumOfObjects):
|
||
pooledObj = self.addObject()
|
||
if (pooledObj is not None):
|
||
pooledObj.setBusy(True)
|
||
logging.info("%s对象已被借用, time:%d", id(pooledObj.getObject()), time.time())
|
||
return pooledObj.getObject()
|
||
# 对象池已满且没有空闲对象,则返回None
|
||
return None
|
||
def returnObject(self, obj):
|
||
for pooledObj in self.__pools:
|
||
if(pooledObj.getObject() == obj):
|
||
pooledObj.setBusy(False)
|
||
logging.info("%s对象已归还, time:%d", id(pooledObj.getObject()), time.time())
|
||
break
|
||
def addObject(self):
|
||
obj = None
|
||
if(len(self.__pools) < ObjectPool.MaxNumOfObjects):
|
||
obj = self.createPooledObject()
|
||
self.__pools.append(obj)
|
||
logging.info("添加新对象%s, time:%d", id(obj), time.time())
|
||
return obj
|
||
def clear(self):
|
||
self.__pools.clear()
|
||
def _findFreeObject(self):
|
||
"查找空闲的对象"
|
||
obj = None
|
||
for pooledObj in self.__pools:
|
||
if(not pooledObj.isBusy()):
|
||
obj = pooledObj.getObject()
|
||
pooledObj.setBusy(True)
|
||
break
|
||
return obj
|
||
</code></pre>
|
||
<h4>类图</h4>
|
||
<p>上面的代码框架可用类图表示如下:</p>
|
||
<p><img src="assets/4c8fba80-9609-11e8-9f67-05ec09da262a.jpg" alt="png" /></p>
|
||
<p>ObjectPool 的一个抽象的对象池,PooledObject 是池对象。实际使用时要实现一个 ObjectPool 的子类并实现 createPooledObject 创建对象的方法;PooledObject 其实是对真实对象的一个包装类,用于控制其是否被占用状态。</p>
|
||
<h4>基于框架的实现</h4>
|
||
<p>有了上面的代码框架之后,我们要实现示例代码的功能就会更简单了。最开始的示例代码假设它为 version 1.0,那么再看看基于框架的 version 2.0 吧。</p>
|
||
<pre><code class="language-python">class PowerBank:
|
||
"移动电源"
|
||
def __init__(self, serialNum, electricQuantity):
|
||
self.__serialNum = serialNum
|
||
self.__electricQuantity = electricQuantity
|
||
self.__user = ""
|
||
def getSerialNum(self):
|
||
return self.__serialNum
|
||
def getElectricQuantity(self):
|
||
return self.__electricQuantity
|
||
def setUser(self, user):
|
||
self.__user = user
|
||
def getUser(self):
|
||
return self.__user
|
||
def showInfo(self):
|
||
print("序列号:%03d 电量:%d%% 使用者:%s" % (self.__serialNum, self.__electricQuantity, self.__user))
|
||
class PowerBankPool(ObjectPool):
|
||
__serialNum = 0
|
||
@classmethod
|
||
def getSerialNum(cls):
|
||
cls.__serialNum += 1
|
||
return cls.__serialNum
|
||
def createPooledObject(self):
|
||
powerBank = PowerBank(PowerBankPool.getSerialNum(), 100)
|
||
return PooledObject(powerBank)
|
||
</code></pre>
|
||
<p>测试代码得稍微改一下:</p>
|
||
<pre><code class="language-python">def testObjectPool():
|
||
powerBankPool = PowerBankPool()
|
||
powerBank1 = powerBankPool.borrowObject()
|
||
if (powerBank1 is not None):
|
||
powerBank1.setUser("Tony")
|
||
powerBank1.showInfo()
|
||
powerBank2 = powerBankPool.borrowObject()
|
||
if (powerBank2 is not None):
|
||
powerBank2.setUser("Sam")
|
||
powerBank2.showInfo()
|
||
powerBankPool.returnObject(powerBank1)
|
||
# powerBank1归还后,不能再对其进行相关操作
|
||
powerBank3 = powerBankPool.borrowObject()
|
||
if (powerBank3 is not None):
|
||
powerBank3.setUser("Aimee")
|
||
powerBank3.showInfo()
|
||
powerBankPool.returnObject(powerBank2)
|
||
powerBankPool.returnObject(powerBank3)
|
||
powerBankPool.clear()
|
||
</code></pre>
|
||
<p>输出结果:</p>
|
||
<pre><code>序列号:001 电量:100% 使用者:Tony
|
||
序列号:002 电量:100% 使用者:Sam
|
||
序列号:001 电量:100% 使用者:Aimee
|
||
</code></pre>
|
||
<h4>设计要点</h4>
|
||
<p>对象池机制有两个核心对象和三个关键动作。</p>
|
||
<ul>
|
||
<li><strong>对象(Object):</strong> 要进行池化的对象,通常是一些创建和销毁时会非常耗时,或对象本身非常占内存的对象。</li>
|
||
<li><strong>对象池(Object Pool):</strong> 对象的集合,其实就是对象的管理器,管理对象的借用、归还。</li>
|
||
<li><strong>借用对象(borrow object):</strong> 从对象池中获取对象。</li>
|
||
<li><strong>使用对象(using object):</strong> 使用对象进行业务逻辑的处理。</li>
|
||
<li><strong>归还对象(return、give back):</strong> 将对象归还对象池;归还后这个对象的引用不能再作它用,除非重新获取对象。</li>
|
||
</ul>
|
||
<h4>对象池机制的优点</h4>
|
||
<p>对象池机制通过借用、归还的思想,实现了对象的重复利用,能有效地节约内存,提升程序性能。</p>
|
||
<h4>对象池机制的缺点</h4>
|
||
<p>但同时也带来一个问题,就是使用者必须自己去负责对象的借用和归还,这里需要注意两点:</p>
|
||
<ul>
|
||
<li>借用和归还必须成对出现,用完后必须归还,不然这个对象将一直处于占用状态。</li>
|
||
<li>已归还的对象的引用,不能再进行任何其他的操作,否则将产生不可预料的结果。</li>
|
||
</ul>
|
||
<p>这就类似于 C 语言中对象内存的分配和释放,程序员必须自己负责内存的申请和释放,给程序带来了很大的负担。</p>
|
||
<p>要解决这个问题,就要使用引用计数的技术。<strong>引用计数的核心相思</strong>是:这个对象每多一个使用者(如对象的赋值和传递时),引用就自动加 1;每少一个使用者(如 del 一个变量,或退出作用域),引用就自动减 1。</p>
|
||
<p>当引用为1时(只有对象池指向这个对象),自动归还(returnObject)给对象池,这样使用者只需要申请一个对象(borrowObject),而不用关心什么时候归还。</p>
|
||
<p>这一部分的实现方式比较复杂,这里将不再详细讲述。引用计数每一门机算机语言的实现方式都各不相同,如 Java 的 Commons-pool 库中就有 SoftReferenceObjectPool 类就是用来解决这个问题的;而 C++ 则可以使用智能指针的方式来实现;Python 的引用计数则是内置了,你可以通过 sys 包中的 getrefcount() 来获得一个对象被引用的数量。</p>
|
||
<h3>应用场景</h3>
|
||
<p>对象池机制特别适用于那些初始化和销毁的代价高,且需要经常被实例化的对象;如大对象、需占用 IO 的对象,这些在创建和销毁时会非常耗时,或对象本身非常占内存的对象。如果是简单的对象,对象的创建和销毁都非常快速,也不吃内存;把它进行池化的时间比自己构建还多,就不划算了。因为对象池的管理本身也是需要占用资源的,如对象的创建、借用、归还这些都是需要消耗资源的。我们经常听到的(数据库)连接池、线程池用到的都是对象池的思想。</p>
|
||
<p>这一课讲的是对象池技术中最核心部分的一种实现,在实际的项目开发中,也有很多成熟的开源项目可以用,比如 Java 语言有 Apache 的 commons-pool 库,就提供了种类多样、功能强大的对象池实现;C++ 语言,也有 Boost 库提供了相应的对象池的功能。</p>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div style="float: left">
|
||
<a href="/专栏/白话设计模式 28 讲(完)/22 深入解读过滤器模式:制作一杯鲜纯细腻的豆浆.md.html">上一页</a>
|
||
</div>
|
||
<div style="float: right">
|
||
<a href="/专栏/白话设计模式 28 讲(完)/24 深入解读回调机制:把你技能亮出来.md.html">下一页</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||
</div>
|
||
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997baf5ac43cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
|
||
</body>
|
||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
|
||
<script>
|
||
window.dataLayer = window.dataLayer || [];
|
||
function gtag() {
|
||
dataLayer.push(arguments);
|
||
}
|
||
gtag('js', new Date());
|
||
gtag('config', 'G-NPSEEVD756');
|
||
var path = window.location.pathname
|
||
var cookie = getCookie("lastPath");
|
||
console.log(path)
|
||
if (path.replace("/", "") === "") {
|
||
if (cookie.replace("/", "") !== "") {
|
||
console.log(cookie)
|
||
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
|
||
}
|
||
} else {
|
||
setCookie("lastPath", path)
|
||
}
|
||
function setCookie(cname, cvalue) {
|
||
var d = new Date();
|
||
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
|
||
var expires = "expires=" + d.toGMTString();
|
||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||
}
|
||
function getCookie(cname) {
|
||
var name = cname + "=";
|
||
var ca = document.cookie.split(';');
|
||
for (var i = 0; i < ca.length; i++) {
|
||
var c = ca[i].trim();
|
||
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
|
||
}
|
||
return "";
|
||
}
|
||
</script>
|
||
</html>
|