C#设计模式之十五迭代器模式(Iterator Pattern)【行为型】
一、引言
今天我们开始讲“行为型”设计模式的第三个模式,该模式是【迭代器模式】,英文名称是: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、迭代器模式的代码实现
迭代器模式在现实生活中也有类似的例子,比如:在部队中,我们可以让某一队伍当中的某人出列,或者让队列里面的每个人依次报名,其实这个过程就是一个遍历的过程。没什么可说的,具体实现代码如下:
namespace 迭代器模式的实现
{
// 部队队列的抽象聚合类--该类型相当于抽象聚合类Aggregate
public interface ITroopQueue
{
Iterator GetIterator();
} // 迭代器抽象类
public interface Iterator
{
bool MoveNext();
Object GetCurrent();
void Next();
void Reset();
} //部队队列具体聚合类--相当于具体聚合类ConcreteAggregate
public sealed class ConcreteTroopQueue:ITroopQueue
{
private string[] collection; public ConcreteTroopQueue()
{
collection = new string[] { "黄飞鸿","方世玉","洪熙官","严咏春" };
} public Iterator GetIterator()
{
return new ConcreteIterator(this);
} public int Length
{
get { return collection.Length; }
} public string GetElement(int index)
{
return collection[index];
}
} // 具体迭代器类
public sealed class ConcreteIterator : Iterator
{
// 迭代器要集合对象进行遍历操作,自然就需要引用集合对象
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++;
} }
} // 客户端(Client)
class Program
{
static void Main(string[] args)
{
Iterator iterator;
ITroopQueue list = new ConcreteTroopQueue();
iterator = list.GetIterator(); while (iterator.MoveNext())
{
string ren = (string)iterator.GetCurrent();
Console.WriteLine(ren);
iterator.Next();
} Console.Read();
}
}
}
三、迭代器模式的实现要点:
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中都实现了IEnumerator接口。
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框架里面也有现成的实现。并且在 Net 2.0里面还有升级的实现,要想学习该模式,可以好好看看该模式在Net 框架中的实现,受益匪浅。
C#设计模式之十五迭代器模式(Iterator Pattern)【行为型】的更多相关文章
- 设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)
设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型) 1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的 ...
- 设计模式(十):从电影院中认识"迭代器模式"(Iterator Pattern)
上篇博客我们从醋溜土豆丝与清炒苦瓜中认识了“模板方法模式”,那么在今天这篇博客中我们要从电影院中来认识"迭代器模式"(Iterator Pattern).“迭代器模式”顾名思义就是 ...
- 二十四种设计模式:迭代器模式(Iterator Pattern)
迭代器模式(Iterator Pattern) 介绍提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示. 示例有一个Message实体类,某聚合对象内的各个元素均为该实体对象,现 ...
- 乐在其中设计模式(C#) - 迭代器模式(Iterator Pattern)
原文:乐在其中设计模式(C#) - 迭代器模式(Iterator Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 迭代器模式(Iterator Pattern) 作者:weba ...
- 设计模式学习--迭代器模式(Iterator Pattern)和组合模式(Composite Pattern)
设计模式学习--迭代器模式(Iterator Pattern) 概述 ——————————————————————————————————————————————————— 迭代器模式提供一种方法顺序 ...
- 设计模式系列之迭代器模式(Iterator Pattern)——遍历聚合对象中的元素
模式概述 模式定义 模式结构图 模式伪代码 模式改进 模式应用 模式在JDK中的应用 模式在开源项目中的应用 模式总结 说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修 ...
- 设计模式 - 迭代器模式(iterator pattern) 具体解释
迭代器模式(iterator pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 迭代器模式(iterator pattern) : 提供一 ...
- 设计模式(十五):Iterator迭代器模式 -- 行为型模式
1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的有用方法,但通常你会处理一组对象或者集合. 集合不一定是均一的.图形用 ...
- C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】
一.引言 今天我们开始讲"行为型"设计模式的第三个模式,该模式是[迭代器模式],英文名称是:Iterator Pattern.还是老套路,先从名字上来看看."迭代器模 ...
随机推荐
- Redis-02.数据类型
Redis中所有数据都是以key-value存储的,value支持的数据类型包括string.hash.list.set.sorted_set 数据类型 string 是redis最基本的类型,一个k ...
- 【分布式缓存系列】集群环境下Redis分布式锁的正确姿势
一.前言 在上一篇文章中,已经介绍了基于Redis实现分布式锁的正确姿势,但是上篇文章存在一定的缺陷——它加锁只作用在一个Redis节点上,如果通过sentinel保证高可用,如果master节点由于 ...
- 传统asp.net小心 async/await坑
最近在改老项目时,干了一件自以为很有成就感的事,心想 “项目都是同步方法,为啥不用异步方法呢?”,于是有了异步方法,类型下面的代码(当然是举例子说明啊) //更新某人名下公司名称 public Tas ...
- 剑指offer面试题17:合并两个排序的链表
题目:输入两个递增排序的链表,合并这两个链表并使新链表中的节点人是按照递增排序的.解题思路:两个链表分别都已经是有序的了,遍历链表的时候只要比较两个链表当前位置大小,取出最小的添加到新链表中. 可以有 ...
- weexpack打包weex项目运行/打包记录
构建weex项目 安装weex-toolkit cnpm install -g weex-toolkit 初始化一个项目只需新建文件夹并在目录下执行 weex init 即可 安装依赖:cnpm in ...
- 为什么要学习 Spring Boot?
我们知道,从 2002 年开始,Spring 一直在飞速的发展,如今已经成为了在Java EE(Java Enterprise Edition)开发中真正意义上的标准,但是随着技术的发展,Java E ...
- MySQL InnoDB 行记录格式(ROW_FORMAT)
MySQL InnoDB 行记录格式(ROW_FORMAT) 一.行记录格式的分类和介绍 在早期的InnoDB版本中,由于文件格式只有一种,因此不需要为此文件格式命名.随着InnoDB引擎的发展,开发 ...
- 使用CSS样式的三种方式
外部样式表 当样式需要被应用到很多页面的时候,外部样式表将是理想的选择.使用外部样式表,你就可以通过更改一个文件来改变整个站点的外观. 内部样式表 当单个文件需要特别样式时,就可以使用内部样式表.你可 ...
- 第69节:Java中数据库的多表操作
第69节:Java中数据库的多表操作 前言 学习数据库的多表操作,去电商行业做项目吧!!! 达叔,理工男,简书作者&全栈工程师,感性理性兼备的写作者,个人独立开发者,我相信你也可以!阅读他的文 ...
- 原生JS-旋转木马
原生JS-旋转木马 今天写一个原生JS写的旋转木马JS效果. 实现原理: 1.建立一个数组给每一张图片写对应的z-index,opacity,top,width: 2.实现旋转的操作是把建造的数组里面 ...