C#设计模式实现之迭代器模式
作者:SpringSun
前言:
迭代器模式平时用的不多,因为不管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); } } }
迭代器模式定义:
迭代器模式:提供一种方法顺序访问一个集合对象中的各个元素,而又不暴露其内部的表示。
迭代器模式让我们能游走于集合内的每一个元素,而又不暴露其内部的表示。
把游走的任务放在迭代器上,而不是集合上。这样简化了集合的接口和实现,也让责任各得其所。
总结
到此这篇关于C#设计模式实现之迭代器模式的文章就介绍到这了,更多相关C#迭代器模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!