欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

设计模式-行为型-迭代器模式

程序员文章站 2022-04-14 20:45:48
迭代器模式(Iterator): 迭代器模式允许你访问一个数据项序列中的所有元素,而无须关心序列是什么类型(数组、链表、列表或任何其他类型)。它能有效地构建一个数据管道,经过一系列不同的转换或过滤后再从管道的另一端出来。迭代器模式就是提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知 ......

迭代器模式(iterator):

  迭代器模式允许你访问一个数据项序列中的所有元素,而无须关心序列是什么类型(数组、链表、列表或任何其他类型)。它能有效地构建一个数据管道,经过一系列不同的转换或过滤后再从管道的另一端出来。迭代器模式就是提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示。

迭代器模式的角色:

  设计模式-行为型-迭代器模式  

  1)抽象迭代器(iterator):接口声明了遍历集合所需的操作(获取下一个元素、获取当前位置和重新开始迭代等)。

  2)具体迭代器(concreteiterator):实现遍历集合的一种特定算法。迭代器对象必须跟踪自身遍历的进度。这使得多个迭代器可以相互独立地遍历同一个集合。

  3)抽象聚合(aggregate):接口声明一个或多个方法来获取与集合兼容的迭代器。返回方法的类型必须被声明为迭代器接口。

  4)具体聚合(concreteaggregate):会在客户端请求迭代器时返回一个特定的具体迭代器类实体

  5)客户端(client):通过集合和迭代器的接口与两者进行交互 这样一来客户端无需与具体类进行耦合 允许同一客户端代码使用各种不同的集合和迭代器

示例:

  先假设有两家餐厅,主营业务不同,一家是早餐店,一家是晚餐店。 

  1 /// <summary>
  2 /// 菜单明细项
  3 /// </summary>
  4 public class menuitem
  5 {
  6     private string name;
  7     private string description;
  8     private bool vegetarin;
  9     private double price;
 10 
 11     public menuitem(string name, string description, bool vegetarin, double price)
 12     {
 13         this.name = name;
 14         this.description = description;
 15         this.vegetarin = vegetarin;
 16         this.price = price;
 17     }
 18 
 19     public string getname()
 20     {
 21         return this.name;
 22     }
 23 
 24     public double getprice()
 25     {
 26         return price;
 27     }
 28 
 29     public bool isvegetarian()
 30     {
 31         return vegetarin;
 32     }
 33 
 34     public string getdescription()
 35     {
 36         return description;
 37     }
 38 }
 39 
 40 /// <summary>
 41 /// 早餐菜单
 42 /// </summary>
 43 public class breakfastmenu
 44 {
 45     private list<menuitem> menuitems;
 46 
 47     public breakfastmenu()
 48     {
 49         menuitems = new list<menuitem>();
 50         additem("牛奶", "牛奶description", false, 3.0);
 51         additem("油条", "油条description", false, 1.0);
 52         additem("馒头", "馒头description", true, 1.0);
 53         additem("豆浆", "doujiangdescription", true, 1.5);
 54     }
 55 
 56     public void additem(string name, string description, bool vegetarian, double price)
 57     {
 58         menuitem menuitem = new menuitem(name, description, vegetarian, price);
 59         menuitems.add(menuitem);
 60     }
 61 
 62     public list<menuitem> getmenuitems()
 63     {
 64         return menuitems;
 65     }
 66 }
 67 
 68 /// <summary>
 69 /// 晚餐菜单
 70 /// </summary>
 71 public class dinnermenu
 72 {
 73     private static readonly int max_items = 6;
 74     private int numberofitems = 0;
 75     private menuitem[] menuitems;
 76 
 77     public dinnermenu()
 78     {
 79         menuitems = new menuitem[max_items];
 80         additem("香菇豆腐饭", "香菇豆腐", false, 10.5);
 81         additem("蛋炒饭", "哈哈", false, 8.5);
 82         additem("鱼香肉丝", "你猜", true, 15.5);
 83     }
 84 
 85     public void additem(string name, string description, bool vegetarian, double price)
 86     {
 87         menuitem menuitem = new menuitem(name, description, vegetarian, price);
 88         if (numberofitems > max_items)
 89         {
 90             console.writeline("菜单已满");
 91         }
 92         else
 93         {
 94             menuitems[numberofitems] = menuitem;
 95             numberofitems++;
 96         }
 97     }
 98 
 99     public menuitem[] getmenuitems()
100     {
101         return menuitems;
102     }
103 }

  现在两家合并了,服务员那菜单的时候就要拿两份菜单。

 1 public static void main(string[] args)
 2 {
 3     breakfastmenu breakfastmenu = new breakfastmenu();
 4     list<menuitem> breakfastitems = breakfastmenu.getmenuitems();
 5 
 6     dinnermenu dinermenu = new dinnermenu();
 7     menuitem[] lunchitems = dinermenu.getmenuitems();
 8 
 9     for (int i = 0; i < breakfastitems.count; i++)
10     {
11         menuitem menuitem = breakfastitems[i] as menuitem;
12         console.writeline(menuitem.getname() + " " + menuitem.getprice().tostring() + " " + menuitem.getdescription().tostring());
13     }
14 
15     for (int j = 0; j < lunchitems.length; j++)
16     {
17         menuitem lunchitem = lunchitems[j];
18         if (lunchitem != null)
19         {
20             console.writeline(lunchitem.getname() + " " + lunchitem.getprice().tostring() + " " + lunchitem.getdescription().tostring());
21         }
22     }
23 }

  我们发现,由于两份菜单数据结构的不同,我们不得不重写多余的代码,显得很臃肿。我们会想:能不能有一个东西能够让我们不需要知道菜单的数据结构,直接就可以获取其内部元素呢?答案是肯定的,这就是我们本节所说的迭代器模式。

  先定义一个接口迭代器并实现晚餐菜单迭代器和晚餐菜单迭代器。

 1 /// <summary>
 2 /// 接口迭代器
 3 /// </summary>
 4 public interface iterator
 5 {
 6     /// <summary>
 7     /// 用来判断下一个元素是否为空
 8     /// </summary>
 9     /// <returns></returns>
10     bool hasnext();
11 
12     /// <summary>
13     /// 用来获取当前元素
14     /// </summary>
15     /// <returns></returns>
16     object next();
17 }
18 
19 /// <summary>
20 /// 早餐菜单迭代器
21 /// </summary>
22 public class breakfastiterator : iterator
23 {
24     private list<menuitem> items;
25     private int position = 0;
26 
27     public breakfastiterator(list<menuitem> items)
28     {
29         this.items = items;
30     }
31 
32     public bool hasnext()
33     {
34         return position <= items.count - 1 && items[position] != null;
35     }
36 
37     public object next()
38     {
39         menuitem item = items[position];
40         position++;
41         return item;
42     }
43 }
44 
45 /// <summary>
46 /// 晚餐菜单迭代器
47 /// </summary>
48 public class dinneriterator : iterator
49 {
50     private menuitem[] items;
51     private int position = 0;
52 
53     public dinneriterator(menuitem[] items)
54     {
55         this.items = items;
56     }
57 
58     public bool hasnext()
59     {
60         return position <= items.length && items[position] != null;
61     }
62 
63     public object next()
64     {
65         menuitem item = items[position];
66         position++;
67         return item;
68     }
69 }

  修改菜单。

 1 /// <summary>
 2 /// 抽象聚合对象,用于创建一个迭代器对象
 3 /// </summary>
 4 public interface imenu
 5 {
 6     iterator createiterator();
 7 }
 8 
 9 /// <summary>
10 /// 早餐菜单
11 /// </summary>
12 public class breakfastmenu : imenu
13 
14 {
15     private list<menuitem> menuitems;
16 
17     public breakfastmenu()
18     {
19         menuitems = new list<menuitem>();
20         additem("牛奶", "牛奶description", false, 3.0);
21         additem("油条", "油条description", false, 1.0);
22         additem("馒头", "馒头description", true, 1.0);
23         additem("豆浆", "doujiangdescription", true, 1.5);
24     }
25 
26     public void additem(string name, string description, bool vegetarian, double price)
27     {
28         menuitem menuitem = new menuitem(name, description, vegetarian, price);
29         menuitems.add(menuitem);
30     }
31 
32     //public list<menuitem> getmenuitems()
33     //{
34     //    return menuitems;
35     //}
36 
37     public iterator createiterator()
38     {
39         return new breakfastiterator(menuitems);
40     }
41 }
42 
43 /// <summary>
44 /// 晚餐菜单
45 /// </summary>
46 public class dinnermenu : imenu
47 
48 {
49     private static readonly int max_items = 6;
50     private int numberofitems = 0;
51     private menuitem[] menuitems;
52 
53     public dinnermenu()
54     {
55         menuitems = new menuitem[max_items];
56         additem("香菇豆腐饭", "香菇豆腐", false, 10.5);
57         additem("蛋炒饭", "哈哈", false, 8.5);
58         additem("鱼香肉丝", "你猜", true, 15.5);
59     }
60 
61     public void additem(string name, string description, bool vegetarian, double price)
62     {
63         menuitem menuitem = new menuitem(name, description, vegetarian, price);
64         if (numberofitems > max_items)
65         {
66             console.writeline("菜单已满");
67         }
68         else
69         {
70             menuitems[numberofitems] = menuitem;
71             numberofitems++;
72         }
73     }
74 
75     //public menuitem[] getmenuitems()
76     //{
77     //    return menuitems;
78     //}
79 
80     public iterator createiterator()
81     {
82         return new dinneriterator(menuitems);
83     }
84 }

  这个时候,两份餐单的输出是这样的。

 1 public static void main(string[] args)
 2 {
 3     imenu breakfastmenu = new breakfastmenu();
 4     imenu dinnermenu = new dinnermenu();
 5     breakfastmenu.createiterator();
 6     iterator dinneriterator = dinnermenu.createiterator();
 7     iterator breakfastiterator = breakfastmenu.createiterator();
 8 
 9     print(breakfastiterator);
10     print(dinneriterator);
11 
12     static void print(iterator iterator)
13     {
14         while (iterator.hasnext())
15         {
16             menuitem menuitem = (menuitem)iterator.next();
17             console.writeline(menuitem.getname() + " " + menuitem.getprice().tostring() + " " + menuitem.getdescription().tostring());
18         }
19     }
20 }

迭代器模式适用性:

  1)当集合背后为复杂的数据结构,且你希望对客户端隐藏其复杂性时(出于使用便利性或安全性的考虑),可以使用迭代器。

  2)可以减少程序中重复的遍历代码。

  3)如果你希望代码能够遍历不同的甚至是无法预知的数据结构,可以使用迭代器。

迭代器模式的优缺点:

  优点:

    1)它支持以不同的方式遍历一个聚合对象。

    2)迭代器简化了聚合类。

    3)在同一个聚合上可以有多个遍历。

    4)在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。符合ocp原则

  缺点:由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

参考: