mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-09-17 08:46:40 +08:00
836 lines
26 KiB
HTML
836 lines
26 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>10 迭代模式:下一个就是你了.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 生活中的设计模式:启程之前,请不要错过我.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/01 监听模式:坑爹的热水器.md.html">01 监听模式:坑爹的热水器.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/02 适配模式:身高不够鞋来凑.md.html">02 适配模式:身高不够鞋来凑.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/03 状态模式:人与水的三态.md.html">03 状态模式:人与水的三态.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/04 单例模式:你是我生命的唯一.md.html">04 单例模式:你是我生命的唯一.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/05 职责模式:我的假条去哪了.md.html">05 职责模式:我的假条去哪了.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/06 中介模式:找房子问中介.md.html">06 中介模式:找房子问中介.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/07 代理模式:帮我拿一下快递.md.html">07 代理模式:帮我拿一下快递.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/08 装饰模式:你想怎么穿就怎么穿.md.html">08 装饰模式:你想怎么穿就怎么穿.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/09 工厂模式:你要拿铁还是摩卡.md.html">09 工厂模式:你要拿铁还是摩卡.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
<a class="current-tab" href="/专栏/白话设计模式 28 讲(完)/10 迭代模式:下一个就是你了.md.html">10 迭代模式:下一个就是你了.md.html</a>
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/11 组合模式:自己组装电脑.md.html">11 组合模式:自己组装电脑.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/12 构建模式:想要车还是庄园.md.html">12 构建模式:想要车还是庄园.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/13 克隆模式:给你一个分身术.md.html">13 克隆模式:给你一个分身术.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/14 策略模式:怎么来不重要,人到就行.md.html">14 策略模式:怎么来不重要,人到就行.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/15 命令模式:大闸蟹,走起!.md.html">15 命令模式:大闸蟹,走起!.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/16 备忘模式:好记性不如烂笔头.md.html">16 备忘模式:好记性不如烂笔头.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/17 享元模式:颜料很贵必须充分利用.md.html">17 享元模式:颜料很贵必须充分利用.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/18 外观模式:学妹别慌,学长帮你.md.html">18 外观模式:学妹别慌,学长帮你.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/19 访问模式:一千个读者一千个哈姆雷特.md.html">19 访问模式:一千个读者一千个哈姆雷特.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/20 生活中的设计模式:与经典设计模式的不解渊源.md.html">20 生活中的设计模式:与经典设计模式的不解渊源.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/21 生活中的设计模式:那些未完待续的设计模式.md.html">21 生活中的设计模式:那些未完待续的设计模式.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/22 深入解读过滤器模式:制作一杯鲜纯细腻的豆浆.md.html">22 深入解读过滤器模式:制作一杯鲜纯细腻的豆浆.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/23 深入解读对象池技术:共享让生活更便捷.md.html">23 深入解读对象池技术:共享让生活更便捷.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/24 深入解读回调机制:把你技能亮出来.md.html">24 深入解读回调机制:把你技能亮出来.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/25 谈谈我对设计模式的理解.md.html">25 谈谈我对设计模式的理解.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/26 谈谈我对设计原则的思考.md.html">26 谈谈我对设计原则的思考.md.html</a>
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/27 谈谈我对项目重构的看法.md.html">27 谈谈我对项目重构的看法.md.html</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>10 迭代模式:下一个就是你了</h1>
|
||
|
||
<p>【故事剧情】</p>
|
||
|
||
<blockquote>
|
||
|
||
<p>Tony 自小就有两颗大牙缺失、腐化,因为父母对牙齿健康的意识太缺失,一直没有治疗过。最近因为上火严重,牙齿更加疼痛,刷牙时水温稍微过低或过高都难耐无比,于是决定自己去医院看牙。</p>
|
||
|
||
<p>周末,Tony 带着医保卡来到空军总医院,这是 Tony 第一次走进北京这种大城市的医院。一楼大厅已经挤满了人,人数多的超过了他的想象。咨询完分诊台,花了近1个小时才排队挂上号:7楼牙科,序号0214,前面还有46人。Tony 坐电梯上了7楼,找到了对应的分诊室的位置,诊室外面等候区的座位已经坐满了人。</p>
|
||
|
||
<p>这里每一个诊室的医生诊断完一个病人之后,会呼叫下一位病人,这时外面的显示屏和语音系统就会自动播报下一位病人的名字。Tony 无聊地看着显示屏,下一位病人0170 Panda,请进入3号分诊室准备就诊;下一位病人0171 Lily……</p>
|
||
|
||
<p>因为人太多,等到12点前面仍然还有12个人,Tony 不得不下去吃个中饭,回来继续等。下一位病人0213 Nick,请进入3号分诊室准备就诊!Tony 眼睛一亮,**哎,妈呀!终于快到了,下一个就是我了!**看了一个时间,正好14:00……</p>
|
||
|
||
</blockquote>
|
||
|
||
<p><img src="assets/47b62430-de18-11e7-9fb6-af685862fa1c.jpg" alt="enter image description here" /></p>
|
||
|
||
<h3>用程序来模拟生活</h3>
|
||
|
||
<p>医院使用排号系统来维持秩序,方便医生和病人。虽然仍然需要排队,且等待是一件非常烦人的事情,但如果没有排号系统,大家都挤在诊室门口将会是更可怕的一件事!这个排号系统就像是病人队伍的大管家,通过数字化的方式精确地维护着先来先就诊的秩序。下面我们用程序来模拟这一场景。</p>
|
||
|
||
<p>源码示例:</p>
|
||
|
||
<pre><code class="language-python">class Customer:
|
||
|
||
"客户"
|
||
def __init__(self, name):
|
||
|
||
self.__name = name
|
||
|
||
self.__num = 0
|
||
|
||
self.__clinics = None
|
||
def getName(self):
|
||
|
||
return self.__name
|
||
def register(self, system):
|
||
|
||
system.pushCustomer(self)
|
||
def setNum(self, num):
|
||
|
||
self.__num = num
|
||
def getNum(self):
|
||
|
||
return self.__num
|
||
def setClinic(self, clinic):
|
||
|
||
self.__clinics = clinic
|
||
def getClinic(self):
|
||
|
||
return self.__clinics
|
||
class Iterator:
|
||
|
||
"迭代器"
|
||
def __init__(self, data):
|
||
|
||
self.__data = data
|
||
|
||
self.__curIdx = -1
|
||
def current(self):
|
||
|
||
return self.__data[self.__curIdx] if(len(self.__data) >= self.__curIdx) else None
|
||
def next(self):
|
||
|
||
if (self.__curIdx < len(self.__data) - 1):
|
||
|
||
self.__curIdx += 1
|
||
|
||
return True
|
||
|
||
else:
|
||
|
||
return False
|
||
class NumeralSystem:
|
||
|
||
"排号系统"
|
||
__clinics = ("1号分诊室", "2号分诊室", "3号分诊室")
|
||
def __init__(self, name):
|
||
|
||
self.__customers = []
|
||
|
||
self.__curNum = 0
|
||
|
||
self.__name = name
|
||
def pushCustomer(self, customer):
|
||
|
||
customer.setNum(self.__curNum + 1)
|
||
|
||
click = NumeralSystem.__clinics[self.__curNum % len(NumeralSystem.__clinics)]
|
||
|
||
customer.setClinic(click)
|
||
|
||
self.__curNum += 1
|
||
|
||
self.__customers.append(customer)
|
||
|
||
print(customer.getName() + "您好!您已在" + self.__name+ "成功挂号,序号:"
|
||
|
||
+ str(customer.getNum()).zfill(4) + ",请耐心等待!")
|
||
def getIterator(self):
|
||
|
||
return Iterator(self.__customers)
|
||
</code></pre>
|
||
|
||
<p>测试代码:</p>
|
||
|
||
<pre><code class="language-python">def testIterator():
|
||
|
||
numeralSystem = NumeralSystem("挂号台")
|
||
|
||
lily = Customer("Lily")
|
||
|
||
lily.register(numeralSystem);
|
||
|
||
pony = Customer("Pony")
|
||
|
||
pony.register(numeralSystem)
|
||
|
||
nick = Customer("Nick")
|
||
|
||
nick.register(numeralSystem)
|
||
|
||
tony = Customer("Tony")
|
||
|
||
tony.register(numeralSystem)
|
||
iterator = numeralSystem.getIterator()
|
||
|
||
while(iterator.next()):
|
||
|
||
customer = iterator.current()
|
||
|
||
print("下一位病人", str(customer.getNum()).zfill(4), customer.getName(), "请到", customer.getClinic(), "就诊。")
|
||
</code></pre>
|
||
|
||
<p>输出结果:</p>
|
||
|
||
<pre><code>Lily您好!您已在挂号台成功挂号,序号:0001,请耐心等待!
|
||
|
||
Pony您好!您已在挂号台成功挂号,序号:0002,请耐心等待!
|
||
|
||
Nick您好!您已在挂号台成功挂号,序号:0003,请耐心等待!
|
||
|
||
Tony您好!您已在挂号台成功挂号,序号:0004,请耐心等待!
|
||
|
||
下一位病人 0001 Lily 请到 1号分诊室 就诊。
|
||
|
||
下一位病人 0002 Pony 请到 2号分诊室 就诊。
|
||
|
||
下一位病人 0003 Nick 请到 3号分诊室 就诊。
|
||
|
||
下一位病人 0004 Tony 请到 1号分诊室 就诊。
|
||
</code></pre>
|
||
|
||
<h3>从剧情中思考迭代器模式</h3>
|
||
|
||
<p>医院的排号系统就像是病人队伍的大管家,通过数字化的方式精确地维护着先来先就诊的秩序。医生不用在乎外面有多少人在等待,更不需要了解每一个人的名字和具体信息。他只要在诊断完一个病人后按一下按钮,排号系统就会自动为他呼叫下一位病人,这样医生就可只专注于病情的诊断!</p>
|
||
|
||
<p>这个排号系统就如同程序设计中的<strong>迭代器模式</strong>:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。迭代器(Iterator)是按照一定的顺序对一个或多个容器中的元素从前往遍历的一种机制,比如 for 循环就是一种最简单的迭代器,对一个数组的遍历也是一种迭代遍历的过程。</p>
|
||
|
||
<p>有人可能会认为上面的实现反而复杂化了,直接一个 for 循环就能遍历所有的病人:</p>
|
||
|
||
<pre><code class="language-python"> def visit(self):
|
||
|
||
for customer in self.__customers:
|
||
|
||
print("下一位病人", str(customer.getNum()).zfill(4), customer.getName(),
|
||
|
||
"请到", customer.getClinic(), "就诊。")
|
||
</code></pre>
|
||
|
||
<p>是的,一开始我也思考过这个问题。因为 Python 本身对迭代器的支持非常好,Python 的很多内置对象本身就是可遍历的(iterable),如 List、Tuple、Dictionary 都是可以遍历的。自定义的容器类,只要实现 <code>\__iter\__</code>和<code>\__next\__</code> 两个方法也可以支持 for … in … 的方式进行遍历。</p>
|
||
|
||
<p>这里还是要以这种方式来实现,主要有两个原因:</p>
|
||
|
||
<ol>
|
||
|
||
<li>for … in … 的方式不能实现医生诊断完一个病人后,呼叫下一个(next)病人的功能。</li>
|
||
|
||
<li>这里讲的迭代器模式是一个一般化的方法,其他的编程语言对迭代器的支持可能并没有这么好。通过这一 Demo 的实现,有助于你更进一步地理解 Python 的 iterable 机制。</li>
|
||
|
||
</ol>
|
||
|
||
<h3>迭代器模式的模型抽象</h3>
|
||
|
||
<h4>迭代器的设计思路</h4>
|
||
|
||
<p>迭代器其实就是维护一个当前的指针,这个指针可以指向当前的元素,可以返回当前所指向的元素,可以移到下一个元素的位置,通过这个指针可以遍历容器的所有元素。迭代器一般至少会有以下两种方法:</p>
|
||
|
||
<ul>
|
||
|
||
<li>current(); // 获得当前所指向的元素</li>
|
||
|
||
<li>next(); // 移至下一个元素</li>
|
||
|
||
</ul>
|
||
|
||
<p><img src="assets/40ccc600-de19-11e7-9fb6-af685862fa1c.jpg" alt="enter image description here" /></p>
|
||
|
||
<p>这是最基本的两个方法,有了这两个方法,就可以从前往后地遍历各个元素。我们也可以增加一些更加丰富的方法,比如实现从后往前遍历。一些更为丰富的迭代器功能:</p>
|
||
|
||
<ul>
|
||
|
||
<li>toBegin() // 将指针移至起始位置</li>
|
||
|
||
<li>toEnd() // 将指针移至结尾位置</li>
|
||
|
||
<li>next() // 往后(下一个)移动一个元素</li>
|
||
|
||
<li>previous() // 往前(上一个)移动一个元素</li>
|
||
|
||
<li>current() // 获取当前的元素</li>
|
||
|
||
</ul>
|
||
|
||
<p>这样可以同时实现往前遍历和往后遍历。</p>
|
||
|
||
<p><img src="assets/526922a0-de19-11e7-962e-6fc770f163b0.jpg" alt="enter image description here" /></p>
|
||
|
||
<h4>基于设计思路的实现</h4>
|
||
|
||
<p>在理解了迭代器的设计思路之后,我们可以为上面示例代码中的迭代器增加一些更丰富的功能,以实现从后往前的遍历。</p>
|
||
|
||
<p>功能更丰富的迭代器:</p>
|
||
|
||
<pre><code class="language-python">class Iterator:
|
||
|
||
"迭代器"
|
||
def __init__(self, data):
|
||
|
||
self.__data = data
|
||
|
||
self.toBegin()
|
||
def toBegin(self):
|
||
|
||
"将指针移至起始位置"
|
||
|
||
self.__curIdx = -1
|
||
def toEnd(self):
|
||
|
||
"将指针移至结尾位置"
|
||
|
||
self.__curIdx = len(self.__data)
|
||
def next(self):
|
||
|
||
"往前移动一个元素"
|
||
|
||
if (self.__curIdx < len(self.__data) - 1):
|
||
|
||
self.__curIdx += 1
|
||
|
||
return True
|
||
|
||
else:
|
||
|
||
return False
|
||
def previous(self):
|
||
|
||
"往后移动一个元素"
|
||
|
||
if (self.__curIdx > 0):
|
||
|
||
self.__curIdx -= 1
|
||
|
||
return True
|
||
|
||
else:
|
||
|
||
return False
|
||
def current(self):
|
||
|
||
"获取当前的元素"
|
||
|
||
return self.__data[self.__curIdx] if (len(self.__data) >= self.__curIdx) else None
|
||
</code></pre>
|
||
|
||
<p>测试代码:</p>
|
||
|
||
<pre><code class="language-python">def testIterator():
|
||
|
||
numeralSystem = NumeralSystem("挂号台")
|
||
|
||
lily = Customer("Lily")
|
||
|
||
lily.register(numeralSystem);
|
||
|
||
pony = Customer("Pony")
|
||
|
||
pony.register(numeralSystem)
|
||
|
||
nick = Customer("Nick")
|
||
|
||
nick.register(numeralSystem)
|
||
|
||
tony = Customer("Tony")
|
||
|
||
tony.register(numeralSystem)
|
||
|
||
print()
|
||
print("从前往后遍历:")
|
||
|
||
iterator = numeralSystem.getIterator()
|
||
|
||
while(iterator.next()):
|
||
|
||
customer = iterator.current()
|
||
|
||
print("下一位病人", str(customer.getNum()).zfill(4), customer.getName(), "请到", customer.getClinic(), "就诊。")
|
||
print("从后往前遍历:")
|
||
|
||
iterator.toEnd()
|
||
|
||
while (iterator.previous()):
|
||
|
||
customer = iterator.current()
|
||
|
||
print("下一位病人", str(customer.getNum()).zfill(4), customer.getName(), "请到", customer.getClinic(), "就诊。")
|
||
</code></pre>
|
||
|
||
<p>输出结果:</p>
|
||
|
||
<pre><code>Lily您好!您已在挂号台成功挂号,序号:0001,请耐心等待!
|
||
|
||
Pony您好!您已在挂号台成功挂号,序号:0002,请耐心等待!
|
||
|
||
Nick您好!您已在挂号台成功挂号,序号:0003,请耐心等待!
|
||
|
||
Tony您好!您已在挂号台成功挂号,序号:0004,请耐心等待!
|
||
从前往后遍历:
|
||
|
||
下一位病人 0001 Lily 请到 1号分诊室 就诊。
|
||
|
||
下一位病人 0002 Pony 请到 2号分诊室 就诊。
|
||
|
||
下一位病人 0003 Nick 请到 3号分诊室 就诊。
|
||
|
||
下一位病人 0004 Tony 请到 1号分诊室 就诊。
|
||
|
||
从后往前遍历:
|
||
|
||
下一位病人 0004 Tony 请到 1号分诊室 就诊。
|
||
|
||
下一位病人 0003 Nick 请到 3号分诊室 就诊。
|
||
|
||
下一位病人 0002 Pony 请到 2号分诊室 就诊。
|
||
|
||
下一位病人 0001 Lily 请到 1号分诊室 就诊。
|
||
</code></pre>
|
||
|
||
<p>说明:在这里从后往前遍历本身是没有意义的(医院不可能后来先就诊),只是为了说明迭代器这一功能的实现方式。</p>
|
||
|
||
<h4>类图</h4>
|
||
|
||
<p>一个迭代器一般对应着一个容器类,而一个容器会包含多个元素,这些元素可能会有不同的子类。他们的关系可表示成如下:</p>
|
||
|
||
<p><img src="assets/796859c0-de19-11e7-962e-6fc770f163b0.jpg" alt="enter image description here" /></p>
|
||
|
||
<p>在实际的项目开发中有可能会有遇到一些更复杂的逻辑。如具有层级关系的组织架构:一个公司有 A、B、C 三个部门,每个部门有自己的部门成员,这时要遍历一个公司的所有成员。这里就会有类似这样的类图关系:</p>
|
||
|
||
<p><img src="assets/93f86e10-de19-11e7-9938-e7a5bced5c2d.jpg" alt="enter image description here" /></p>
|
||
|
||
<p>这里公司就对应 Container,部门就对应 Group。我们并不遍历 Group,而是按照一定的顺序遍历 Group 的每一个成员,一个 Group 遍历完后,再遍历下一个 Group。这样使用者只需要调用迭代 next() 方法就可以遍历所有的成员,而不用关注内部的组织架构。</p>
|
||
|
||
<h4>模型说明</h4>
|
||
|
||
<h5><strong>迭代器模式的优点</strong></h5>
|
||
|
||
<ol>
|
||
|
||
<li>迭代器模式将存储数据和遍历数据的职责分离。</li>
|
||
|
||
<li>简化了聚合数据的访问方式。</li>
|
||
|
||
<li>可支持多种不同的方式(如顺序和逆序)遍历一个聚合对象。</li>
|
||
|
||
</ol>
|
||
|
||
<h5><strong>迭代器模式的缺点</strong></h5>
|
||
|
||
<p>需要额外增加迭代器的功能实现,增加新的聚合类时,可能需要增加新的迭代器。</p>
|
||
|
||
<h3>应用场景</h3>
|
||
|
||
<ol>
|
||
|
||
<li>集合的内部结构复杂,不想暴露对象的内部细节,只提供精简的访问方式。</li>
|
||
|
||
<li>需要提供统一的访问接口,从而对不同的集合使用同一的算法。</li>
|
||
|
||
<li>需要为一系列聚合对象提供多种不同的访问方式。</li>
|
||
|
||
</ol>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div>
|
||
|
||
<div style="float: left">
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/09 工厂模式:你要拿铁还是摩卡.md.html">上一页</a>
|
||
|
||
</div>
|
||
|
||
<div style="float: right">
|
||
|
||
<a href="/专栏/白话设计模式 28 讲(完)/11 组合模式:自己组装电脑.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":"70997b90bc7a3cfa","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>
|
||
|