天天看点

10 迭代器模式

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

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

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

类图如下:

10 迭代器模式

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

代码如下:

 MenuItem规定了菜单的统一格式

10 迭代器模式
10 迭代器模式

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 Name
13         {
14             get { return name; }
15             set { name = value; }
16         }
17         string description;
18 
19         public string Description
20         {
21             get { return description; }
22             set { description = value; }
23         }
24         bool isVegetarian;
25 
26         public bool IsVegetarian
27         {
28             get { return isVegetarian; }
29             set { isVegetarian = value; }
30         }
31         double price;
32 
33         public double Price
34         {
35             get { return price; }
36             set { price = value; }
37         }
38     }      

View Code

DinerMenu类

10 迭代器模式
10 迭代器模式
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             else
32             {
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     }      

PancakeHouseMenu类

10 迭代器模式
10 迭代器模式
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     }      

迭代器

10 迭代器模式
10 迭代器模式
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             else
23             {
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 : Iterator
38     {
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             else
53             {
54                 return true;
55             }
56         }
57 
58         public object Next()
59         {
60 
61             MenuItem item = items[position];
62             position++;
63             return item;
64         }
65     }      

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

10 迭代器模式
10 迭代器模式
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     }      

测试代码

10 迭代器模式
10 迭代器模式
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     }      

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

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

继续阅读