经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
设计模式-行为型-迭代器模式
来源:cnblogs  作者:酷学大叔  时间:2019/10/8 11:04:05  对本文有异议

迭代器模式(Iterator):

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

迭代器模式的角色:

    

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

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

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

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

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

示例:

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

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

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

  1. 1 public static void Main(string[] args)
  2. 2 {
  3. 3 BreakfastMenu breakfastMenu = new BreakfastMenu();
  4. 4 List<MenuItem> breakfastItems = breakfastMenu.GetMenuItems();
  5. 5
  6. 6 DinnerMenu dinerMenu = new DinnerMenu();
  7. 7 MenuItem[] lunchItems = dinerMenu.GetMenuItems();
  8. 8
  9. 9 for (int i = 0; i < breakfastItems.Count; i++)
  10. 10 {
  11. 11 MenuItem menuItem = breakfastItems[i] as MenuItem;
  12. 12 Console.WriteLine(menuItem.GetName() + " " + menuItem.GetPrice().ToString() + " " + menuItem.GetDescription().ToString());
  13. 13 }
  14. 14
  15. 15 for (int j = 0; j < lunchItems.Length; j++)
  16. 16 {
  17. 17 MenuItem lunchItem = lunchItems[j];
  18. 18 if (lunchItem != null)
  19. 19 {
  20. 20 Console.WriteLine(lunchItem.GetName() + " " + lunchItem.GetPrice().ToString() + " " + lunchItem.GetDescription().ToString());
  21. 21 }
  22. 22 }
  23. 23 }

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

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

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

  修改菜单。

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

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

  1. 1 public static void Main(string[] args)
  2. 2 {
  3. 3 IMenu breakfastMenu = new BreakfastMenu();
  4. 4 IMenu dinnerMenu = new DinnerMenu();
  5. 5 breakfastMenu.CreateIterator();
  6. 6 Iterator dinnerIterator = dinnerMenu.CreateIterator();
  7. 7 Iterator breakfastIterator = breakfastMenu.CreateIterator();
  8. 8
  9. 9 Print(breakfastIterator);
  10. 10 Print(dinnerIterator);
  11. 11
  12. 12 static void Print(Iterator iterator)
  13. 13 {
  14. 14 while (iterator.HasNext())
  15. 15 {
  16. 16 MenuItem menuItem = (MenuItem)iterator.Next();
  17. 17 Console.WriteLine(menuItem.GetName() + " " + menuItem.GetPrice().ToString() + " " + menuItem.GetDescription().ToString());
  18. 18 }
  19. 19 }
  20. 20 }

迭代器模式适用性:

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

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

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

迭代器模式的优缺点:

  优点:

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

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

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

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

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

参考:https://www.cnblogs.com/lzhp/p/3427704.html

原文链接:http://www.cnblogs.com/az4215/p/11630073.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号