C#设计模式之16-迭代器模式
迭代器模式(Iterator Pattern)
该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/417 访问。
迭代器模式属于行为型模式,它提供一种方法顺序访问一个聚合对象中的各种元素,而又不暴露该对象的内部表示,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。
角色:
1、迭代器(Iterator)
迭代器角色负责定义访问和遍历元素的接口;
2、具体迭代器(Concrete Iteraror)
具体迭代器角色实现了迭代器接口,并需要记录遍历中的当前位置;
3、聚合(Aggregate)
聚合角色负责定义获得迭代器角色的接口;
4、具体聚合(Concrete Aggregate)
具体聚合角色实现聚合角色接口。
示例:
命名空间IteratorPattern中包含Person基类、People类、PelpleEnum类,另外包含一个苹果手机ApplePhone类,和BestEnum类。Person示例来自微软官方的IEnumerable接口介绍页面,BestEnum则使用.Net 2.0中的yield return关键字创建苹果手机信息序列。
namespace IteratorPattern
一、传统迭代器实现
public class Person {
public string FirstName { get; set; }
public string LastName { get; set; }
public Person(string firstName, string lastName) {
this.FirstName = firstName;
this.LastName = lastName;
}
}
Person类,包含First Name和Last Name。
public class People : IEnumerable {
private Person[] _people = null;
public People(Person[] pArray) {
_people = new Person[pArray.Length];
for (int i = 0; i < pArray.Length; i++) {
_people[i] = pArray[i];
}
}
public IEnumerator GetEnumerator() {
return new PeopleEnum(_people);
}
}
People类,实现IEnumerable接口。
public class PeopleEnum : IEnumerator {
private Person[] _people = null;
private int _cursor = -1;
public PeopleEnum(Person[] list) {
_people = list;
}
public bool MoveNext() {
_cursor++;
return (_cursor < _people.Length);
}
public void Reset() {
_cursor = -1;
}
public object Current {
get {
try {
return _people[_cursor];
}
catch (IndexOutOfRangeException) {
throw new InvalidOperationException();
}
}
}
}
PeopleEnum类,实现IEnumerator接口。
二、yield return迭代器实现
yield关键字向编译器指示它所在的方法是迭代器块,yield return返回一个迭代器的状态机。
C#开发笔记之05-迭代器中的状态机(State Machine)到底是什么?
public class ApplePhone {
public string PhoneName { get; set; }
public DateTime PublishedDate { get; set; }
}
ApplePhone类,包含手机名称和发布日期。
public class BestEnum {
public static IEnumerable<ApplePhone> GetIPhones() {
yield return new ApplePhone {
PhoneName = "IPhone",
PublishedDate = new DateTime(2007, 1, 9)
};
yield return new ApplePhone {
PhoneName = "IPhone 3G",
PublishedDate = new DateTime(2008, 6, 10)
};
yield return new ApplePhone {
PhoneName = "IPhone 3GS",
PublishedDate = new DateTime(2009, 6, 9)
};
yield return new ApplePhone {
PhoneName = "IPhone 4",
PublishedDate = new DateTime(2010, 6, 8)
};
//部分代码已省略
}
}
BestEnum类,包含GetIPhones方法返回苹果手机信息的序列。
public class Program {
protected const string LINE_BREAK =
"---------------------------------------------";
public static void Main(string[] args) {
var peopleArray = new Person[]
{
new Person("John", "Smith"),
new Person("Jim", "Johnson"),
new Person("Sue", "Rabon")
};
var peopleList = new People(peopleArray);
foreach(Person p in peopleList)
Console.WriteLine(p.FirstName + " " + p.LastName);
Console.WriteLine(LINE_BREAK);
var iterator = peopleList.GetEnumerator();
while(iterator.MoveNext()) {
var person = iterator.Current as Person;
Console.WriteLine(person.FirstName + " " + person.LastName);
}
Console.WriteLine(LINE_BREAK);
foreach(var phone in BestEnum.GetIPhones()) {
Console.WriteLine("[" + phone.PhoneName + "] was released in " +
phone.PublishedDate.ToString("yyyy-MM-dd") + "!");
}
Console.WriteLine(LINE_BREAK);
Console.ReadKey();
}
}
以上是调用方的代码,以下是这个案例的输出结果:
John Smith
Jim Johnson
Sue Rabon
---------------------------------------------
John Smith
Jim Johnson
Sue Rabon
---------------------------------------------
[IPhone] was released in 2007-01-09!
[IPhone 3G] was released in 2008-06-10!
[IPhone 3GS] was released in 2009-06-09!
[IPhone 4] was released in 2010-06-08!
[IPhone 4s] was released in 2011-10-04!
[IPhone 5] was released in 2012-09-13!
[IPhone 5S] was released in 2013-09-10!
[IPhone 5C] was released in 2013-09-10!
[IPhone 6] was released in 2014-09-10!
[IPhone 6 Plus] was released in 2014-09-10!
[IPhone 6s] was released in 2015-09-10!
[IPhone 6s Plus] was released in 2015-09-10!
[IPhone 7] was released in 2016-09-08!
[IPhone 7 Plus] was released in 2016-09-08!
[IPhone 8] was released in 2017-09-13!
[IPhone 8 Plus] was released in 2017-09-13!
[IPhone X] was released in 2017-09-13!
---------------------------------------------
优点:
该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/417 访问。
1、迭代器模式使得访问一个聚合对象的内容而无需暴露它的内部表示,即迭代抽象;
2、迭代器模式为遍历不同的集合结构提供了一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。
缺点:
1、迭代器模式在遍历的同时更改迭代器所在的集合结构会导致出现异常。所以使用foreach语句只能在对集合进行遍历,不能在遍历的同时更改集合中的元素。
使用场景:
1、系统需要访问一个聚合对象的内容而无需暴露它的内部表示;
2、系统需要支持对聚合对象的多种遍历;
3、系统需要为不同的聚合结构提供一个统一的接口。
C#设计模式之16-迭代器模式的更多相关文章
- 设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)
设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型) 1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的 ...
- 《Head first设计模式》之迭代器模式
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示. 爆炸性新闻:对象村餐厅和对象村煎饼屋合并了! 真是个好消息!现在我们可以在同一个地方,享用煎饼屋美味的煎饼早餐,和好吃 ...
- [设计模式] 16 迭代器模式 Iterator Pattern
在GOF的<设计模式:可复用面向对象软件的基础>一书中对迭代器模式是这样说的:提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该对象的内部表示. 类图和实例: 迭代器模式由以下角 ...
- C#设计模式(16)——迭代器模式(Iterator Pattern)
一.引言 在上篇博文中分享了我对命令模式的理解,命令模式主要是把行为进行抽象成命令,使得请求者的行为和接受者的行为形成低耦合.在一章中,将介绍一下迭代器模式.下面废话不多说了,直接进入本博文的主题. ...
- 设计模式のIteratorPattern(迭代器模式)----行为模式
一.产生背景 迭代器模式(Iterator Pattern)是 Java 和 .Net 编程环境中非常常用的设计模式.这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示. 二.实现方式 ...
- Java设计模式学习记录-迭代器模式
前言 这次要介绍的是迭代器模式,也是一种行为模式.我现在觉得写博客有点应付了,前阵子一天一篇,感觉这样其实有点没理解透彻就写下来了,而且写完后自己也没有多看几遍,上次在面试的时候被问到java中的I/ ...
- 大话设计模式Python实现-迭代器模式
迭代器模式(Iterator Pattern):提供方法顺序访问一个聚合对象中各元素,而又不暴露该对象的内部表示. 下面是一个迭代器模式的demo: #!/usr/bin/env python # - ...
- 设计模式系列之迭代器模式(Iterator Pattern)——遍历聚合对象中的元素
模式概述 模式定义 模式结构图 模式伪代码 模式改进 模式应用 模式在JDK中的应用 模式在开源项目中的应用 模式总结 说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修 ...
- 重学 Java 设计模式:实战迭代器模式「模拟公司组织架构树结构关系,深度迭代遍历人员信息输出场景」
作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 相信相信的力量! 从懵懂的少年,到拿起键盘,可以写一个Hell ...
- C#设计模式系列:迭代器模式(Iterator)
迭代器模式把对象的职责分离,职责分离可以最大限度减少彼此之间的耦合程度,从而建立一个松耦合的对象.职责分离的要点是对被分离的职责进行封装,并以抽象的方式建立彼此之间的关系. 1.迭代器模式简介 1.1 ...
随机推荐
- Apache Kylin v3.1.0 重点功能推介
Apache Kylin v3.1.0 已于上周正式发布,其中包含了许多值得一试的新功能,本文选择了 Presto 查询下压引擎.Flink 构建引擎.Kylin on Kubernetes 解决方案 ...
- Java常用API(Math类)
Java常用API(Math类) Math类的作用 java.lang.Math 类包含用于执行基本数学运算的方法,如初等指数.对数.平方根和三角函数.类似这样的工具 类,其所有方法均为静态方法,并且 ...
- Docker 基础知识 - 使用绑定挂载(bind mounts)管理应用程序数据
绑定挂载(bind mounts)在 Docker 的早期就已经出现了.与卷相比,绑定挂载的功能有限.当您使用绑定挂载时,主机上的文件或目录将挂载到容器中.文件或目录由其在主机上的完整或相对路径引用. ...
- DICOM 相关概念了解
前言: 正如前述文章中提到的,DICOM(Digitial Image Communications in Medicine)是所有从事医学影像处理的工作者需要了解的最基本的图像格式. 假 ...
- ICPC North Central NA Contest 2018
目录 ICPC North Central NA Contest 2018 1. 题目分析 2. 题解 A.Pokegene B.Maximum Subarrays C.Rational Ratio ...
- shell 中的${},##, %% , :- ,:+, ? 的使用
假设我们定义了一个变量为:file=/dir1/dir2/dir3/my.file.txt 可以用${ }分别替换得到不同的值:${file#*/}:删掉第一个/ 及其左边的字符串:dir1/dir2 ...
- 在Dockerfile中使用和“Source”的Run指令不起作用?
报错误 /bin/sh: 1: source: not found sh不支持source bash支持source RUN rm /bin/sh && ln -s /bin/bash ...
- Springboot 多数据源配置,结合tk-mybatis
一.前言 作为一个资深的CRUD工程师,我们在实际使用springboot开发项目的时候,难免会遇到同时使用多个数据库的情况,比如前脚刚查询mysql,后脚就要查询sqlserver. 这时,我们很直 ...
- 如何验证 names(名称), e-mails(邮件), 和 URLs
PHP 表单 - 验证邮件和URL 本章节我们将介绍如何验证 names(名称), e-mails(邮件), 和 URLs. PHP - 验证名称 以下代码将通过简单的方式来检测 name 字段是否包 ...
- PHP array_diff_uassoc() 函数
实例 比较两个数组的键名和键值(使用用户自定义函数比较键名),并返回差集: <?phpfunction myfunction($a,$b){if ($a===$b){return 0;}retu ...