首页 > 代码库 > 10 迭代器模式

10 迭代器模式

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

实际上现在很多语言都自带迭代器,无需我们单独实现,比如c#中的foreach-in,但通过学习迭代器模式,我们可以看到类似foreach-in这种语法背后的逻辑,同时感受一下GOF所在的那个时代大神们的创造力。

c#中foreach-in是语言内置迭代器的语法糖,List、数组、Dictionary等等都可以使用foreach方便地遍历,这也正是迭代器的好处,被遍历的对象不需要暴露自己内部的表示,这样遍历的代码就可以和被遍历对象解耦。

类图如下:

技术分享

示例代码使用Head Forst设计模式中的例子,煎饼屋的菜单PancakeHouseMenu使用List存放,餐厅的菜单DinerMenu使用数组存放,两者合并后,为了能够统一地展示他们的菜单项,使用迭代器模式处理

代码如下:

 MenuItem规定了菜单的统一格式

技术分享
 1 class MenuItem 2     { 3         public MenuItem(string name, string description, bool isVegetarian, double price) 4         { 5             this.name = name; 6             this.description = description; 7             this.isVegetarian = isVegetarian; 8             this.price = price; 9         }10         string name;11 12         public string Name13         {14             get { return name; }15             set { name = value; }16         }17         string description;18 19         public string Description20         {21             get { return description; }22             set { description = value; }23         }24         bool isVegetarian;25 26         public bool IsVegetarian27         {28             get { return isVegetarian; }29             set { isVegetarian = value; }30         }31         double price;32 33         public double Price34         {35             get { return price; }36             set { price = value; }37         }38     }
View Code

DinerMenu类

技术分享
 1 class DinerMenu 2     { 3         static readonly int MAX_ITEMS = 6; 4         int numberOfItems = 0; 5         MenuItem[] menuItem; 6         public DinerMenu() 7         { 8             menuItem = new MenuItem[MAX_ITEMS]; 9             AddItem("Vegetarian BLT",10                           "(Fakin‘) Bacon with lettuce&tomato on whole wheat",11                             true, 2.99);12             AddItem("BLT",13                           "Bacon with lettuce&tomato on whole wheat",14                             false, 2.99);15             AddItem("Soup of the Day",16                           "Soup of the Day, with a side of potato salad",17                             false, 3.29);18             AddItem("HotDog",19                           "A hot dog, with saurkraut, relish, onions, topped with chesse",20                             false, 3.05);21 22         }23 24         public void AddItem(string name, string description, bool isVegetarian, double price)25         {26             MenuItem item = new MenuItem(name, description, isVegetarian, price);27             if (numberOfItems >= MAX_ITEMS)28             {29                 Console.WriteLine("Over Flow!!!");30             }31             else32             {33                 menuItem[numberOfItems] = item;34                 numberOfItems++;35             }36         }37 38         public MenuItem[] GetMenuItems()39         {40             return menuItem;41         }42 43         public Iterator CreateIterator()44         {45             return new DinerMenuIterator(menuItem);46         }47     }
View Code

PancakeHouseMenu类

技术分享
 1 class PancakeHouseMenu 2     { 3         List<MenuItem> listMenu = new List<MenuItem>(); 4         public PancakeHouseMenu() 5         { 6             MenuItem item = new MenuItem( 7                 "K&B‘s Pancake Breakfast", 8                 "Pancakes with scrambled eggs, and toast", 9                 true,10                 2.99);11             listMenu.Add(item);12             item = new MenuItem(13                "Regular Pancake Breakfast",14                "Pancakes with fired eggs, sausage",15                false,16                2.99);17             listMenu.Add(item);18             item = new MenuItem(19                "Blueberry Pancake",20                "Pancakes made with fresh blueberry",21                true,22                3.49);23             listMenu.Add(item);24             item = new MenuItem(25                "Waffles",26                "Waffles, with your choice of blueberries or strawberries",27                true,28                3.59);29             listMenu.Add(item);30         }31 32         public void AddItem(string name, string description, bool isVegetarian, double price)33         {34             MenuItem item = new MenuItem(name, description, isVegetarian, price);35             listMenu.Add(item);36         }37         public List<MenuItem> GetMenu()38         {39             return listMenu;40         }41 42         public Iterator CreateIterator()43         {44             return new PancakeHouseIterator(listMenu);45         }46     }
View Code

迭代器

技术分享
 1 interface Iterator 2     { 3         bool HaveNext(); 4         object Next(); 5     } 6  7     class DinerMenuIterator : Iterator 8     { 9         MenuItem[] items;10         int position = 0;11         public DinerMenuIterator(MenuItem[] items)12         {13             this.items = items;14         }15 16         public bool HaveNext()17         {18             if (position >= items.Length || items[position] == null)19             {20                 return false;21             }22             else23             {24                 return true;25             }26         }27 28         public object Next()29         {30 31             MenuItem item = items[position];32             position++;33             return item;34         }35     }36 37     class PancakeHouseIterator : Iterator38     {39         List<MenuItem> items;40         int position = 0;41         public PancakeHouseIterator(List<MenuItem> items)42         {43             this.items = items;44         }45 46         public bool HaveNext()47         {48             if (position >= items.Count)49             {50                 return false;51             }52             else53             {54                 return true;55             }56         }57 58         public object Next()59         {60 61             MenuItem item = items[position];62             position++;63             return item;64         }65     }
View Code

Waitress,服务员,相当于迭代器的使用者

技术分享
 1 class Waitress 2     { 3         DinerMenu dinerMenu; 4         PancakeHouseMenu pancakeMenu; 5         public Waitress(DinerMenu dinerMenu, PancakeHouseMenu pancakeMenu) 6         { 7             this.dinerMenu = dinerMenu; 8             this.pancakeMenu = pancakeMenu; 9         }10         public void PrintMenu()11         {12             Iterator dinerIterator = dinerMenu.CreateIterator();13             Iterator pancakeIterator = pancakeMenu.CreateIterator();14             Console.WriteLine("Diner@@@@@@@");15             PrineMenu(dinerIterator);16             Console.WriteLine("Pancake@@@@@@");17             PrineMenu(pancakeIterator);18         }19 20         private void PrineMenu(Iterator iterator)21         {22             while (iterator.HaveNext())23             {24                 MenuItem item = (MenuItem)iterator.Next();25                 Console.WriteLine(string.Format("{0} {1} {2}",item.Name,item.Description,item.Price));26             }27         }28     }
View Code

测试代码

技术分享
 1 class Program 2     { 3         static void Main(string[] args) 4         { 5             DinerMenu dinerMenu = new DinerMenu(); 6             PancakeHouseMenu pancakeMenu = new PancakeHouseMenu(); 7             Waitress waitress = new Waitress(dinerMenu, pancakeMenu); 8             waitress.PrintMenu(); 9             Console.ReadKey();10         }11     }
View Code

 

单一职责原则:一个类应该只有一个引起变化的原因。

比如前文中的菜单,使用迭代器之前,菜单既要负责存储项目,又要负责展示,每次给菜单新增内容时都要都是修改这两方面的功能,造成了维护上的不便,而维护上的不便有可能带来逻辑上的混乱进而引发bug。可见,单一职责原则是很有指导意义的。

10 迭代器模式