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 ...
随机推荐
- php代码没解析成功
在Apache中加载PHP模块 1.打开Apache的配置文件httpd.conf(位于Apache2\conf 目录下). 2.查找 “#LoadModule ssl_module modules/ ...
- 【javaScript】加减乘除的精确计算
在js中使用"+"."-"等符号进行运算会出现很大的误差,所以需要自己创建函数进行精确运算. //说明:javascript的加法结果会有误差,在两个浮点数相加 ...
- idea初使用之自动编译
原文地址:https://blog.csdn.net/diaomeng11/article/details/73826564/ 因为公司需要,方便使用框架以及代码整合,使用同一开发集成环境idea,因 ...
- 自定义BeanDefinitionRegistryPostProcessor注册bean
自定义BeanDefinitionRegistryPostProcessor 概述 BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProce ...
- java线程基础梳理
java线程 概述 进程:运行时概念,运行的应用程序,进程间不能共享内存 线程:应用程序内并发执行的代码段,可以共享堆内存和方法区内存,而栈内存是独立的. 并发理解:在单核机器上,从微观角度来看,一段 ...
- 使用nutz框架,找不到入口函数,访问Url报404
案例 今天在跟着nutz框架教程去配置demo时,发现访问URL找不到入口函数,出现了Search mapping for path=/user/count : NOT Action match 异常 ...
- 【大白话系列】MySQL 学习总结 之 初步了解 MySQL 的架构设计
一.MySQL还是个黑盒子 我们都知道,只要我们系统引入了 MySQL 驱动和连接池,就能从数据库连接池获取一个数据库连接,然后就可以执行增删改查的操作了. 可是我们并不知道 MySQL 里面是怎么执 ...
- python笔记04
数据类型(二) 今日内容 1.列表 2.元组 内容回顾和补充 1.计算机基础 ①硬件:cpu,内存,硬盘,主板,网卡 ②操作系统:linux,centos, Ubuntu,redhat windows ...
- JVM源码分析之警惕存在内存泄漏风险的FinalReference(增强版)
概述 JAVA对象引用体系除了强引用之外,出于对性能.可扩展性等方面考虑还特地实现了四种其他引用:SoftReference.WeakReference.PhantomReference.FinalR ...
- pyhon学习Day18--继承
[知识点] 面向对象的三大特性:继承.多态.封装 [继承] (1)继承:class Person(Animal): ——括号里的:父类,基类,超类 括号外的:子类,派生类 class Animal ...