当前位置: 移动技术网 > IT编程>软件设计>设计模式 > 设计模式-行为型-迭代器模式

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

2019年10月08日  | 移动技术网IT编程  | 我要评论

迭代器模式(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原则

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

参考:

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网