C#设计模式学习笔记:(15)迭代器模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7903617.html,记录一下学习过程以备后续查用。
一、引言
今天我们要讲行为型设计模式的第三个模式--迭代器模式,先从名字上来看。迭代是遍历的意思,迭代器可以理解为是遍历某某的工具,遍历什么呢?在软
件设计中,当然遍历的是集合对象,所以说迭代器模式是遍历集合的一种通用的算法。如果集合只有一种类型,那这个模式就没用了,就是因为集合对象包含
数组、列表、字典和哈希表等各种对象。如果为每一种集合对象都实现一套遍历算法,也不太现实,因此为了解决遍历集合有一个统一的接口这个事情,所以
就提出了“迭代器”这个模式。
二、迭代器模式介绍
迭代器模式:英文名称--Iterator Pattern;分类--行为型。
2.1、动机(Motivate)
在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包
含的元素,同时这种“透明遍历”也为“同一种算法在多种集合对象上进行操作”提供了可能。
使用面向对象技术将这种遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了一种优雅的方式。
2.2、意图(Intent)
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。——《设计模式》GoF
2.3、结构图
2.4、模式的组成
从迭代器模式的结构图可以看出,它涉及到四个角色,它们分别是:
1)抽象迭代器(Iterator):抽象迭代器定义了访问和遍历元素的接口,一般声明以下方法:用于获取第一个元素的first()、用于访问下一个元素的next()、用于
判断是否还有下一个元素的hasNext()、用于获取当前元素的currentItem(),在其子类中将实现这些方法。
2)具体迭代器(ConcreteIterator):具体迭代器实现了抽象迭代器接口,完成对集合对象的遍历,同时在对聚合进行遍历时跟踪其当前位置。
3)抽象聚合类(Aggregate):抽象聚合类用于存储对象,并定义创建相应迭代器对象的接口,声明一个createIterator()方法用于创建一个迭代器对象。
4)具体聚合类(ConcreteAggregate):具体聚合类实现了创建相应迭代器的接口,实现了在抽象聚合类中声明的createIterator()方法,并返回一个与该具体聚
合相对应的具体迭代器ConcreteIterator实例。
2.5、迭代器模式的具体实现
迭代器模式在现实生活中也有类似的例子,比如:在部队中,我们可以让某一队伍当中的某人出列,或者让队列里面的每个人依次报名,其实这个过程就是
一个遍历的过程。具体实现代码如下:
class Program
{
/// <summary>
/// 部队队列的抽象聚合类--该类型相当于抽象聚合类Aggregate
/// </summary>
public interface ITroopQueue
{
IIterator GetIterator();
} /// <summary>
/// 迭代器抽象类
/// </summary>
public interface IIterator
{
bool MoveNext();
object GetCurrent();
void Next();
void Reset();
} /// <summary>
/// 部队队列具体聚合类--相当于具体聚合类ConcreteAggregate
/// </summary>
public sealed class ConcreteTroopQueue : ITroopQueue
{
private string[] collection; public ConcreteTroopQueue()
{
collection = new string[] { "黄飞鸿", "方世玉", "洪熙官", "严咏春" };
} public IIterator GetIterator()
{
return new ConcreteIterator(this);
} public int Length
{
get { return collection.Length; }
} public string GetElement(int index)
{
return collection[index];
}
} /// <summary>
/// 具体迭代器类
/// </summary>
public sealed class ConcreteIterator : IIterator
{
//迭代器要对集合对象进行遍历操作,自然就需要引用集合对象。
private ConcreteTroopQueue _list;
private int _index; public ConcreteIterator(ConcreteTroopQueue list)
{
_list = list;
_index = ;
} public bool MoveNext()
{
if (_index < _list.Length)
{
return true;
}
return false;
} public Object GetCurrent()
{
return _list.GetElement(_index);
} public void Reset()
{
_index = ;
} public void Next()
{
if (_index < _list.Length)
{
_index++;
}
}
} static void Main(string[] args)
{
#region 迭代器模式
IIterator iterator;
ITroopQueue list = new ConcreteTroopQueue();
iterator = list.GetIterator();
while (iterator.MoveNext())
{
string name = (string)iterator.GetCurrent();
Console.WriteLine(name);
iterator.Next();
} Console.Read();
#endregion
}
}
运行结果如下:
三、迭代器模式的实现要点
1)迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。
2)迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。
3)迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。
3.1、迭代器模式的优点
1)迭代器模式使得访问一个聚合对象的内容而无需暴露它的内部表示,即迭代抽象。
2)迭代器模式为遍历不同的集合结构提供了一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。
3.2、迭代器模式的缺点
1)迭代器模式在遍历的同时更改迭代器所在的集合结构会导致出现异常,所以使用foreach语句只能在对集合进行遍历,不能在遍历的同时更改集合中的元素。
3.3、迭代器模式的使用场景
1)访问一个聚合对象的内容而无需暴露它的内部表示。
2)支持对聚合对象的多种遍历。
3)为遍历不同的聚合结构提供一个统一的接口(即支持多态迭代)。
四、.NET中迭代器模式的实现
在mscorlib程序集里有这样一个命名空间:System.Collections,在该命名空间里面早已有了迭代器模式的实现。对于聚集接口和迭代器接口已经存在了,其中
IEnumerator扮演的就是迭代器的角色,它的实现如下:
public interface IEnumerator
{
object Current
{
get;
} bool MoveNext(); void Reset();
}
属性Current返回当前集合中的元素;Reset()方法恢复初始化指向的位置;MoveNext()方法返回值true表示迭代器成功前进到集合中的下一个元素,返回值false
表示已经位于集合的末尾,能够以此来提供元素的遍历。
在.Net中IEnumerable扮演的就是抽象聚集的角色,只有一个GetEnumerator()方法,如果集合对象需要具备迭代遍历的功能,就必须实现该接口。
public interface IEnumerable
{
IEumerator GetEnumerator();
}
抽象聚合角色(Aggregate)和抽象迭代器角色(Iterator)分别是IEnumerable接口和IEnumerator接口,具体聚合角色(ConcreteAggregate)有Queue、BitArray
等类型,代码如下:
public sealed class BitArray : ICollection, IEnumerable, ICloneable
{
[Serializable]
private class BitArrayEnumeratorSimple : IEnumerator, ICloneable
{
private BitArray bitarray; private int index; private int version; private bool currentElement; public virtual object Current
{
get
{
if (this.index == -)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumNotStarted"));
}
if (this.index >= this.bitarray.Count)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumEnded"));
}
return this.currentElement;
}
} internal BitArrayEnumeratorSimple(BitArray bitarray)
{
this.bitarray = bitarray;
this.index = -;
this.version = bitarray._version;
} public object Clone()
{
return base.MemberwiseClone();
} public virtual bool MoveNext()
{
if (this.version != this.bitarray._version)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
}
if (this.index < this.bitarray.Count - )
{
this.index++;
this.currentElement = this.bitarray.Get(this.index);
return true;
}
this.index = this.bitarray.Count;
return false;
} public void Reset()
{
if (this.version != this.bitarray._version)
{
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion"));
}
this.index = -;
}
} private const int BitsPerInt32 = ; private const int BytesPerInt32 = ; private const int BitsPerByte = ; private int[] m_array; private int m_length; private int _version; [NonSerialized]
private object _syncRoot; private const int _ShrinkThreshold = ; [__DynamicallyInvokable]
public bool this[int index]
{
[__DynamicallyInvokable]
get
{
return this.Get(index);
}
[__DynamicallyInvokable]
set
{
this.Set(index, value);
}
} [__DynamicallyInvokable]
public int Length
{
[__DynamicallyInvokable]
get
{
return this.m_length;
}
[__DynamicallyInvokable]
set
{
if (value < )
{
throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
int arrayLength = BitArray.GetArrayLength(value, );
if (arrayLength > this.m_array.Length || arrayLength + < this.m_array.Length)
{
int[] array = new int[arrayLength];
Array.Copy(this.m_array, array, (arrayLength > this.m_array.Length) ? this.m_array.Length : arrayLength);
this.m_array = array;
}
if (value > this.m_length)
{
int num = BitArray.GetArrayLength(this.m_length, ) - ;
int num2 = this.m_length % ;
if (num2 > )
{
this.m_array[num] &= ( << num2) - ;
}
Array.Clear(this.m_array, num + , arrayLength - num - );
}
this.m_length = value;
this._version++;
}
} public int Count
{
get
{
return this.m_length;
}
} public object SyncRoot
{
get
{
if (this._syncRoot == null)
{
Interlocked.CompareExchange<object>(ref this._syncRoot, new object(), null);
}
return this._syncRoot;
}
} public bool IsReadOnly
{
get
{
return false;
}
} public bool IsSynchronized
{
get
{
return false;
}
} private BitArray()
{
} [__DynamicallyInvokable]
public BitArray(int length) : this(length, false)
{
} [__DynamicallyInvokable]
public BitArray(int length, bool defaultValue)
{
if (length < )
{
throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
this.m_array = new int[BitArray.GetArrayLength(length, )];
this.m_length = length;
int num = defaultValue ? - : ;
for (int i = ; i < this.m_array.Length; i++)
{
this.m_array[i] = num;
}
this._version = ;
} [__DynamicallyInvokable]
public BitArray(byte[] bytes)
{
if (bytes == null)
{
throw new ArgumentNullException("bytes");
}
if (bytes.Length > )
{
throw new ArgumentException(Environment.GetResourceString("Argument_ArrayTooLarge", new object[]
{ }), "bytes");
}
this.m_array = new int[BitArray.GetArrayLength(bytes.Length, )];
this.m_length = bytes.Length * ;
int num = ;
int num2 = ;
while (bytes.Length - num2 >= )
{
this.m_array[num++] = ((int)(bytes[num2] & ) | (int)(bytes[num2 + ] & ) << | (int)(bytes[num2 + ] & ) << | (int)(bytes[num2 + ] & ) << );
num2 += ;
}
switch (bytes.Length - num2)
{
case :
goto IL_103;
case :
break;
case :
this.m_array[num] = (int)(bytes[num2 + ] & ) << ;
break;
default:
goto IL_11C;
}
this.m_array[num] |= (int)(bytes[num2 + ] & ) << ;
IL_103:
this.m_array[num] |= (int)(bytes[num2] & );
IL_11C:
this._version = ;
} [__DynamicallyInvokable]
public BitArray(bool[] values)
{
if (values == null)
{
throw new ArgumentNullException("values");
}
this.m_array = new int[BitArray.GetArrayLength(values.Length, )];
this.m_length = values.Length;
for (int i = ; i < values.Length; i++)
{
if (values[i])
{
this.m_array[i / ] |= << i % ;
}
}
this._version = ;
} [__DynamicallyInvokable]
public BitArray(int[] values)
{
if (values == null)
{
throw new ArgumentNullException("values");
}
if (values.Length > )
{
throw new ArgumentException(Environment.GetResourceString("Argument_ArrayTooLarge", new object[]
{ }), "values");
}
this.m_array = new int[values.Length];
this.m_length = values.Length * ;
Array.Copy(values, this.m_array, values.Length);
this._version = ;
} [__DynamicallyInvokable]
public BitArray(BitArray bits)
{
if (bits == null)
{
throw new ArgumentNullException("bits");
}
int arrayLength = BitArray.GetArrayLength(bits.m_length, );
this.m_array = new int[arrayLength];
this.m_length = bits.m_length;
Array.Copy(bits.m_array, this.m_array, arrayLength);
this._version = bits._version;
} [__DynamicallyInvokable]
public bool Get(int index)
{
if (index < || index >= this.Length)
{
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
return (this.m_array[index / ] & << index % ) != ;
} [__DynamicallyInvokable]
public void Set(int index, bool value)
{
if (index < || index >= this.Length)
{
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
if (value)
{
this.m_array[index / ] |= << index % ;
}
else
{
this.m_array[index / ] &= ~( << index % );
}
this._version++;
} [__DynamicallyInvokable]
public void SetAll(bool value)
{
int num = value ? - : ;
int arrayLength = BitArray.GetArrayLength(this.m_length, );
for (int i = ; i < arrayLength; i++)
{
this.m_array[i] = num;
}
this._version++;
} [__DynamicallyInvokable]
public BitArray And(BitArray value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (this.Length != value.Length)
{
throw new ArgumentException(Environment.GetResourceString("Arg_ArrayLengthsDiffer"));
}
int arrayLength = BitArray.GetArrayLength(this.m_length, );
for (int i = ; i < arrayLength; i++)
{
this.m_array[i] &= value.m_array[i];
}
this._version++;
return this;
} [__DynamicallyInvokable]
public BitArray Or(BitArray value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (this.Length != value.Length)
{
throw new ArgumentException(Environment.GetResourceString("Arg_ArrayLengthsDiffer"));
}
int arrayLength = BitArray.GetArrayLength(this.m_length, );
for (int i = ; i < arrayLength; i++)
{
this.m_array[i] |= value.m_array[i];
}
this._version++;
return this;
} [__DynamicallyInvokable]
public BitArray Xor(BitArray value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (this.Length != value.Length)
{
throw new ArgumentException(Environment.GetResourceString("Arg_ArrayLengthsDiffer"));
}
int arrayLength = BitArray.GetArrayLength(this.m_length, );
for (int i = ; i < arrayLength; i++)
{
this.m_array[i] ^= value.m_array[i];
}
this._version++;
return this;
} [__DynamicallyInvokable]
public BitArray Not()
{
int arrayLength = BitArray.GetArrayLength(this.m_length, );
for (int i = ; i < arrayLength; i++)
{
this.m_array[i] = ~this.m_array[i];
}
this._version++;
return this;
} public void CopyTo(Array array, int index)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (index < )
{
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
if (array.Rank != )
{
throw new ArgumentException(Environment.GetResourceString("Arg_RankMultiDimNotSupported"));
}
if (array is int[])
{
Array.Copy(this.m_array, , array, index, BitArray.GetArrayLength(this.m_length, ));
return;
}
if (array is byte[])
{
int arrayLength = BitArray.GetArrayLength(this.m_length, );
if (array.Length - index < arrayLength)
{
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
}
byte[] array2 = (byte[])array;
for (int i = ; i < arrayLength; i++)
{
array2[index + i] = (byte)(this.m_array[i / ] >> i % * & );
}
return;
}
else
{
if (!(array is bool[]))
{
throw new ArgumentException(Environment.GetResourceString("Arg_BitArrayTypeUnsupported"));
}
if (array.Length - index < this.m_length)
{
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
}
bool[] array3 = (bool[])array;
for (int j = ; j < this.m_length; j++)
{
array3[index + j] = ((this.m_array[j / ] >> j % & ) != );
}
return;
}
} public object Clone()
{
return new BitArray(this.m_array)
{
_version = this._version,
m_length = this.m_length
};
} [__DynamicallyInvokable]
public IEnumerator GetEnumerator()
{
return new BitArray.BitArrayEnumeratorSimple(this);
} private static int GetArrayLength(int n, int div)
{
if (n <= )
{
return ;
}
return (n - ) / div + ;
}
}
还有很多类型,就不一一列举了,大家可以查看源代码,每个元素都可以在迭代器模式的构造图上找到对应的元素,具体的类型和代码截图如下:
五、总结
想要深入学习迭代器模式,可以好好看看该模式在.Net框架中的实现,一定会让你受益匪浅。
C#设计模式学习笔记:(15)迭代器模式的更多相关文章
- 设计模式学习笔记--备忘录(Mamento)模式
写在模式学习之前 什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方式,这就是软件模式:每个模式描写叙述了一个在我们程序设计中常常发生的问题,以及该问题的解决方式:当我们碰到模 ...
- 设计模式学习笔记-Adapter模式
Adapter模式,就是适配器模式,使两个原本没有关联的类结合一起使用. 平时我们会经常碰到这样的情况,有了两个现成的类,它们之间没有什么联系,但是我们现在既想用其中一个类的方法,同时也想用另外一个类 ...
- Java-马士兵设计模式学习笔记-装饰者模式
Java装饰者模式简介 一.假设有一个Worker接口,它有一个doSomething方法,Plumber和Carpenter都实现了Worker接口,代码及关系如下: 1.Worker.java p ...
- 研磨设计模式学习笔记2--外观模式Facade
需求:客户端需要按照需求,执行一个操作,操作包括一个系统中的3个模块(根据配置选择是否全部执行). 外观模式优点: 客户端无需知道系统内部实现,,只需要写好配置文件,控制那些模块执行,简单易用. 外观 ...
- 设计模式学习笔记 1.factory 模式
Factory 模式 用户不关心工厂的具体类型,只知道这是一个工厂就行. 通过工厂的实现推迟到子类里面去来确定工厂的具体类型. 工厂的具体类型来确定生产的具体产品. 同时用户不关心这是一个什么样子的产 ...
- 设计模式学习笔记——Composite 组合模式
用于描述无限层级的复杂对象,类似于描述资源管理器,抽象出每一个层级的共同特点(文件夹和文件,展开事件) 以前描述一个对象,是将整个对象的全部数据都描述清楚,而组合模式通过在对象中定义自己,描述自己的下 ...
- 设计模式学习笔记——Bridge 桥接模式
先说一下我以前对桥接模式的理解:当每个类中都使用到了同样的属性或方法时,应该将他们单独抽象出来,变成这些类的属性和方法(避免重复造轮子),当时的感觉是和三层模型中的model有点单相似,也就是让mod ...
- 设计模式学习笔记——Visitor 访问者模式
1.定义IVisitor接口,确定变化所涉及的方法 2.封装变化类.实现IVisitor接口 3.在实体类的变化方法中传入IVisitor接口,由接口确定使用哪一种变化来实现(封装变化) 4.在使用时 ...
- Java-马士兵设计模式学习笔记-责任链模式-FilterChain功能
一.目标 增加filterchain功能 二.代码 1.Filter.java public interface Filter { public String doFilter(String str) ...
- Java-马士兵设计模式学习笔记-责任链模式-处理数据
一.目标 数据提交前做各种处理 二.代码 1.MsgProcessor.java public class MsgProcessor { private List<Filter> filt ...
随机推荐
- Java入门 - 语言基础 - 05.基本数据类型
原文地址:http://www.work100.net/training/java-basic-datatype.html 更多教程:光束云 - 免费课程 基本数据类型 序号 文内章节 视频 1 概述 ...
- 「 优质资源20190409 」Java最新精选优质资源!
资源导读 经过小编精心整理,java最新优质资源出炉 不想看书,可以看视频,比较生动有趣,好的视频教程是一个好老师! 资源来自于网络,请勿用于商业用途 资源目录 1.Java Spring 技术栈构建 ...
- [ Python入门教程 ] Python中JSON模块基本使用方法
JSON (JavaScript Object Notation)是一种使用广泛的轻量数据格式,Python标准库中的json模块提供了一种简单的方法来编码和解码JSON格式的数据.用于完成字符串和p ...
- Python里使用转义字符\r时遇到的问题
在Pycharm里使用转义字符\r和在IDLE里使用\r产生的结果是不一样的. 例子如下: print("你好!\r我是Python!") 输出结果为: 我是Python! 前面的 ...
- nginx文件压缩
nginx文件压缩 如果我们租用了一个带宽很低的服务器,网站访问速度会很慢,这时我们可以通过让nginx开启GZIP压缩来提高网站的访问速度. 首先我们对nginx进行限速操作,限制每个连接的访问速度 ...
- Linux 常用工具openssh之ssh
前言 ssh是openssh套件中的客户端连接工具,可以给予ssh加密协议实现安全的远程登录服务器 语法 ssh (选项) (参数) 选项 -:强制使用ssh协议版本1: -:强制使用ssh协议版本2 ...
- Centos 7 下部署集群式阿波罗
apollo工作原理 用户通过浏览器登录Portal管理界面 >> 通过Admin server对配置进行修改 >> 应用程序主动向config server配置注意:Port ...
- SOAP与REST API的爱恨情仇
之前一直想写些RESTful相关的文章,却一直未付诸行动.直到最近接手一个新的项目,对这块重新温习,乘此机会写些相关帖子.欢迎大家评论留言,如有错漏之处,也望各位大佬不令赐教. 话不多说,干活顶上. ...
- String、StringBuilder、StringBuffer区别
=====================================String=================================★1.它在java.lang包中.String类 ...
- SDL多线程显示更新窗口
//初始化SDL2和创建一个窗口,并且将屏幕绘制成大红色 #include <iostream> extern "C" { #include <SDL.h> ...