前言:迭代器模式平时用的不多,因为不管C#还是Java都已经帮我封装了,但是你是否知道平时经常在用的东西本质是怎么回事呢。

看完迭代器模式你就知道C# foreach循环是怎么实现的了,我的另一篇C# Foreach循环本质与枚举器就讲解了foreach的本质,其中用到的就是迭代器模式。

按照惯例,例子走起。(写了几个小时浏览器崩溃,我看见在自动保存啊,结果没内容,再撸一遍精简点的吧)

一、餐馆合并菜单

现在有两个餐馆和并,其中一个餐馆做早餐,一个做晚餐。他们都有自己管理菜单的方式,现在两个餐馆合并需要对菜单进行统一管理,先让我来看看他们原来的样子。

两个菜单的菜单项都是一样的

  菜单项

    public class MenuItme
{
//名字
public string Name { get; set; }
//描述
public string Description { get; set; }
//是否素菜
public bool Vegetarian { get; set; }
//价格
public double Price { get; set; } public MenuItme(string name, string description, bool vegetarian, double price) {
Name = name;
Description=description;
Vegetarian = vegetarian;
Price = price;
}
}

  早餐菜单,使用List管理,不限制长度

    public class BreakFastMenu
{
private List<MenuItme> menuItmes;
public BreakFastMenu()
{
menuItmes = new List<MenuItme>();
AddItem("梅菜扣肉饼", "好吃", false, 7);
//菜单项...
} public void AddItem(string name, string description, bool vegetarian, double price)
{
MenuItme menuItme = new MenuItme(name, description, vegetarian, price);
menuItmes.Add(menuItme);
} public List<MenuItme> GetMenuItmes()
{
return menuItmes;
}
}

  晚餐菜单,使用数组管理,限制长度为6

    public class DinerMenu
{
static readonly int Max_Items = 6;
private int numberOfImtes = 0;
private MenuItme[] menuItmes;
public DinerMenu()
{
menuItmes = new MenuItme[Max_Items];
AddItem("爆炒癞蛤蟆", "讲究火候", false, 42);
//菜单项...
} public void AddItem(string name, string description, bool vegetarian, double price)
{
MenuItme menuItme = new MenuItme(name, description, vegetarian, price);
if (numberOfImtes >= Max_Items)
{
Console.WriteLine("菜单已满");
}
else
{
menuItmes[numberOfImtes] = menuItme;
numberOfImtes++;
}
} public MenuItme[] GetMenuItmes()
{
return menuItmes;
}
}

  当两个餐馆合并后需要打印早餐和晚餐菜单给顾客用。

            BreakFastMenu breakFastMenu = new BreakFastMenu();
List<MenuItme> breakFastMenus = breakFastMenu.GetMenuItmes(); DinerMenu dinerMenu = new DinerMenu();
MenuItme[] dinerMenus = dinerMenu.GetMenuItmes();
//打印早餐
for (int i = 0; i < breakFastMenus.Count; i++)
{
Console.WriteLine(breakFastMenus[i].Name);
}
//打印晚餐
for (int i = 0; i < dinerMenus.Length; i++)
{
Console.WriteLine(dinerMenus[i].Name);
}

按照这种做法我们总是需要处理两个菜单,如果要打印素食,那么也需要循环遍历两个菜单。

假如加入第三家餐厅合并,我们就需要循环处理三次,显然这种方式会让我们系统难以维护。

接下来看我们如何进行改进

二、改进菜单实现

计模式就是要封装变化的部分,很明显,这里变化是:不同的集合类所造成的遍历,我们如何封装遍历集合

不管早餐还是晚餐我们都要用到中括号[ ] 来取菜单项,集合长度来限制长度。

现在我们要创建一个对象,将他称为迭代器(Iterator),利用它来封装“遍历集合内的每个对象的过程”。

  对于List

            Iterator iterator = breakFastMenu.CreateIterator();
while (iterator.HasNext)
{
MenuItme menuItme = iterator.Next(); }

  

  对于数组

            Iterator iterator = dinerFastMenu.CreateIterator();
while (iterator.HasNext)
{
MenuItme menuItme = iterator.Next(); }

现在两个集合的遍历都统一了,而这种方式正是迭代器模式。关于迭代器我们需要知道的第一件事情,就是它依赖于一个迭代器接口。

这个接口可能有HasNext()方法高数我们是否在这个集合中还有更多的元素。

Next()方法返回这个集合中的下一个对象。一旦我们有了这个接口,就可以为各种对象集合实现迭代器。

现在我们对晚餐菜单进行改造,首先我们需要定义一个迭代器接口

    public interface Iterator
{
bool HasNext();
Object Next();
}

  加入一个晚餐菜单迭代器

    public class DinerMenuIterator : Iterator
{
MenuItme[] menuItmes;
int position = 0; public DinerMenuIterator(MenuItme[] menuItmes)
{
this.menuItmes = menuItmes;
}
public bool HasNext()
{
//由于数组是固定长度,不仅要检查数组,还要检查指定位置是否为空,如果为空后面就没有菜单项了
if (position >= menuItmes.Length || menuItmes[position] == null)
return false;
else
return true;
} public object Next()
{
MenuItme menuItme = menuItmes[position];
position++;
return menuItme;
}
}

  用迭代器改写晚餐菜单

    public class DinerMenu
{
static readonly int Max_Items = 6;
private int numberOfImtes = 0;
private MenuItme[] menuItmes;
public DinerMenu()
{
menuItmes = new MenuItme[Max_Items];
AddItem("爆炒癞蛤蟆", "讲究火候", false, 42);
//菜单项...
} public void AddItem(string name, string description, bool vegetarian, double price)
{
MenuItme menuItme = new MenuItme(name, description, vegetarian, price);
if (numberOfImtes >= Max_Items)
{
Console.WriteLine("菜单已满");
}
else
{
menuItmes[numberOfImtes] = menuItme;
numberOfImtes++;
}
}
public Iterator CreateIterator()
{
return new DinerMenuIterator(menuItmes);
}
//public MenuItme[] GetMenuItmes()
//{
// return menuItmes;
//}
}

  同理我们为早餐加入迭代器

    public class BreakFastIterator: Iterator
{
List<MenuItme> menuItmes;
int position = 0; public BreakFastIterator(List<MenuItme> menuItmes)
{
this.menuItmes = menuItmes;
}
public bool HasNext()
{
if (position >= menuItmes.Count)
return false;
else
return true;
} public object Next()
{
MenuItme menuItme = menuItmes[position];
position++;
return menuItme;
}
}

  用迭代器改写早餐菜单

    public class BreakFastMenu
{
private List<MenuItme> menuItmes;
public BreakFastMenu()
{
menuItmes = new List<MenuItme>();
AddItem("梅菜扣肉饼", "好吃", false, 7);
//菜单项...
} public void AddItem(string name, string description, bool vegetarian, double price)
{
MenuItme menuItme = new MenuItme(name, description, vegetarian, price);
menuItmes.Add(menuItme);
}
public Iterator CreateIterator()
{
return new BreakFastIterator(menuItmes);
}
//public List<MenuItme> GetMenuItmes()
//{
// return menuItmes;
//}
}

  好了,让我们试一试迭代器工作情况

三、迭代器模式

经过第二步我们基本已经实现迭代器模式,最后我们再改良一下打印菜单,并对菜单进行统一接口的管理。

定义一个Menu接口

     public interface Menu
{
Iterator CreateIterator();
}

让早餐晚餐都实现Menu接口,并封装一个新的菜单打印

    public class NewMenu
{
Menu breakFastMenu;
Menu dinerMenu;
public NewMenu(Menu breakFastMenu, Menu dinerMenu) {
this.breakFastMenu = breakFastMenu;
this.dinerMenu = dinerMenu;
} public void PrintMenu() { Iterator breakFastIterator = breakFastMenu.CreateIterator();
Console.WriteLine("新菜单--------早餐");
PrintMenu(breakFastIterator);
Console.WriteLine("新菜单--------晚餐");
Iterator dinerIterator = dinerMenu.CreateIterator();
PrintMenu(dinerIterator);
} private void PrintMenu(Iterator iterator) {
while (iterator.HasNext())
{
//取得下一个项
MenuItme menuItme = (MenuItme)iterator.Next();
Console.WriteLine(menuItme.Name);
}
}
}

  

迭代器模式定义:

迭代器模式:提供一种方法顺序访问一个集合对象中的各个元素,而又不暴露其内部的表示。

迭代器模式让我们能游走于集合内的每一个元素,而又不暴露其内部的表示。

把游走的任务放在迭代器上,而不是集合上。这样简化了集合的接口和实现,也让责任各得其所。

Head First设计模式——迭代器模式的更多相关文章

  1. 19. 星际争霸之php设计模式--迭代器模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  2. java设计模式——迭代器模式

    一. 定义与类型 定义:提供一种方法,顺序访问一个集合对象中的各个元素,而又不暴露该对象的内部表示 类型:行为型. 二. 使用场景 (1) 访问一个集合对象的内容而无需暴露它的内部表示 (2)  为遍 ...

  3. [Head First设计模式]生活中学设计模式——迭代器模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  4. JAVA 设计模式 迭代器模式

    用途 迭代器模式 (Iterator) 提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示. 迭代器模式是一种行为型模式. 结构

  5. 深入浅出设计模式——迭代器模式(Iterator Pattern)

    模式动机 一个聚合对象,如一个列表(List)或者一个集合(Set),应该提供一种方法来让别人可以访问它的元素,而又不需要暴露它的内部结构.针对不同的需要,可能还要以不同的方式遍历整个聚合对象,但是我 ...

  6. JavaScript设计模式 - 迭代器模式

    迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示. 迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺 ...

  7. javascript设计模式-迭代器模式(Iterator)

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. 设计模式 --迭代器模式(Iterator)

    能够游走于聚合内的每一个元素,同时还可以提供多种不同的遍历方式.   基本概念: 就是提供一种方法顺序访问一个聚合对象中的各个元素,而不是暴露其内部的表示.   使用迭代器模式的优点: 遍历集合或者数 ...

  9. js设计模式--迭代器模式

    迭代器模式: 迭代器模式提供一种方法顺序访问一个聚合对象中各个元素,而又不需要暴露该方法中的内部表示.js中我们经常会封装一个each函数用来实现迭代器. 理解的意思:提供一个方法,去把对象的每一项按 ...

  10. javascript设计模式——迭代器模式

    前面的话 迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示.迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即使不关心对象的内部构造,也 ...

随机推荐

  1. 关于GC(上):Apache的POI组件导致线上频繁FullGC问题排查及处理全过程

    某线上应用在进行查询结果导出Excel时,大概率出现持续的FullGC.解决这个问题时,记录了一下整个的流程,也可以作为一般性的FullGC问题排查指导. 1. 生成dump文件 为了定位FullGC ...

  2. 苹果审核ipv6海外解决思路-About APP Store

    原始简书文章地址(也是我自己的) 首先声明,一我不负责涉及你们内部服务器. 二是好好读文章,别人能过,你们也能过 苹果6月1日出的IPV6协议阻碍了国内大多数积极开发者,我司也不外乎,经过三次被拒后, ...

  3. m102 SE赛

    这次考试考完试正在刷提交记录的时候,到我这突然oj卡了一下,然后卡了大约10s,再刷出来就发现:

  4. Python脚本之——API自动化框架总结

    学完了Python脚本接口自动化之后,一直没有对该框架做总结,今天终于试着来做一份总结了. 框架结构如下图: 来说一下每个目录的作用: Configs:该目录下存放的是.conf,.ini文件格式的配 ...

  5. 『题解』洛谷P1993 小K的农场

    更好的阅读体验 Portal Portal1: Luogu Description 小\(K\)在\(\mathrm MC\)里面建立很多很多的农场,总共\(n\)个,以至于他自己都忘记了每个农场中种 ...

  6. 2019年10月13日 linux习题 wangqingchao

    1. GUN的含义是: GNU's Not UNIX . 2. Linux一般有3个主要部分:内核.命令解释层.实用工具. 3.POSIX是可携式操作系统接口的缩写,重点在规范核心与应用程序之间的接口 ...

  7. H5+app,自动更新后自动删除安装包

    H5+app 自动删除安装包 一.前言 之前做好的app自动更新,遗留下了一个问题,就是自动更新后安装包没有自行删除掉. 好像现在的手机的系统是有安装完自动清理安装包的.想我这个H5+的app安装完后 ...

  8. javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: ResultSet is from UPDATE. No Data.

    Java jpa调用存储过程,抛出异常如下: javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCEx ...

  9. ReentrantLock 如何实现非公平锁?和公平锁实现有什么区别

    reentrant 英[riːˈɛntrənt] 美[ˌriˈɛntrənt] 先学会读.单词原意是可重入的 考察显示锁的使用.可延伸知识点 独占锁 & 共享锁 独占锁 - 悲观锁(不能同时被 ...

  10. nyoj 198-数数 (python, string[::-1])

    198-数数 内存限制:64MB 时间限制:3000ms 特判: No 通过数:16 提交数:25 难度:2 题目描述: 我们平时数数都是喜欢从左向右数的,但是我们的小白同学最近听说德国人数数和我们有 ...