标签:
1引言
迭代这个名词对于熟悉Java的人来说绝对不陌生。我们常常使用JDK提供的迭代接口进行java collection的遍历:
1 Iterator it = list.iterator(); 2 while(it.hasNext()){ 3 //using “it.next();”do some businesss logic 4 }
而这就是关于迭代器模式应用很好的例子。
简而言之,什么是迭代器呢?
比如有一个Apple类,然后很多apple的时候,可以用Apple类型的Arraylist aplist,或者Apple类型的数组aparray。那么遍历所有苹果的时候,就需要在arraylist内部和数组内部对游标不停的自增来实现遍历,就像遍历数组时i=0;i<arrary.length...
聚合对象:Apple类型的Arraylist aplist或者Apple类型的数组aparray就是聚合对象,是对Apple类的聚合。
迭代元素:遍历的每一个aplist或者aparray中的元素就是迭代元素(Apple类型的)
即迭代元素的任务是聚合对象完成的。
使用迭代器模式,就是用另外的对象(迭代器对象)来实现对聚合对象的遍历。
简单理解迭代器:就是有一个方形的苹果篮(对应上面的Arraylist),还有一个圆形的苹果篮(对应上面的数组),没有迭代器时,篮子自己检查内部的数量并从中取一个出来。有了迭代器时,迭代器就相当于一个机器人,它负责从篮中取苹果的任务。初始化机器人时,把篮子给它扫描一下(获取了篮子中的arraylist/array,以及苹果的数量)。这就是迭代器模式。
2.迭代器模式定义:
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而不是暴露其内部的表示。
3.迭代器例子--早餐和晚餐菜单的显示
不用迭代器时:
由于早餐和晚餐其数据结构不同,由于早餐店和晚餐店需要合并,所以需要一个统一的菜单:即菜单项结构相同。下面先介绍一下菜单项的结构。
菜单项信息:菜单名,介绍,荤素,价格
1 public class MenuItem 2 { 3 private string name; 4 private string description; 5 private bool vegetarin; 6 private double price; 7 //构造方法 8 public MenuItem(string name, string description, bool vegetarin, double price) 9 { 10 this.name = name; 11 this.description = description; 12 this.vegetarin = vegetarin; 13 this.price = price; 14 } 15 16 public string GetName() 17 { 18 return name; 19 } 20 21 public double GetPrice() 22 { 23 return price; 24 } 25 26 public bool IsVegetarian() 27 { 28 return vegetarin; 29 } 30 31 public string GetDescription() 32 { 33 return description; 34 } 35 }
接下来分别来看一下早餐类和晚餐类,早餐类的结构是ArrayList,晚餐类的结构是数组:
早餐菜单类:
1 public class BreakfastMenu 2 { 3 ArrayList menuItems; 4 public BreakfastMenu() 5 { 6 menuItems = new ArrayList(); 7 AddItem("牛奶", "牛奶description", false, 3.0); 8 AddItem("油条","油条description",false,1.0); 9 AddItem("馒头","馒头description",true,1.0); 10 AddItem("豆浆", "DoujiangDescription", true, 1.5); 11 } 12 13 public void AddItem(string name, string description, bool vegetarian, double price) 14 { 15 MenuItem menuItem = new MenuItem( name, description, vegetarian, price); 16 menuItems.Add(menuItem); 17 } 18 //外部获取 menuItems信息,(arraylist类型) 19 public ArrayList GetMenuItems() 20 { 21 return menuItems; 22 } 23 }
晚餐菜单类:
1 public class DinerMenu 2 { 3 static readonly int Max_ITEMS = 6; 4 int numberOfItems = 0; 5 MenuItem[] menuItems; 6 7 public DinerMenu() 8 { 9 menuItems = new MenuItem[Max_ITEMS]; 10 AddItem("香菇豆腐饭", "香菇豆腐", false, 10.5); 11 AddItem("蛋炒饭","哈哈",false,8.5); 12 AddItem("鱼香肉丝","你猜",true,15.5); 13 } 14 15 public void AddItem(string name, string description, bool vegetarian, double price) 16 { 17 MenuItem menuItem = new MenuItem(name, description, vegetarian, price); 18 if (numberOfItems>Max_ITEMS) 19 { 20 Console.WriteLine("菜单已满"); 21 } 22 else 23 { 24 menuItems[numberOfItems] = menuItem; 25 numberOfItems++; 26 } 27 }
//外部获取 munuItems数组 28 public MenuItem[] GetMenuItems() 29 { 30 return menuItems; 31 } 32 }
接下来看一下客户端是如何来把各种饭菜打印出来的:
1 BreakfastMenu breakfastMenu = new BreakfastMenu(); 2 ArrayList breakfastItems = breakfastMenu.GetMenuItems(); 3 4 DinerMenu dinerMenu = new DinerMenu(); 5 MenuItem[] lunchItems = dinerMenu.GetMenuItems(); 6 7 //遍历arraylist 8 for (int i = 0; i < breakfastItems.Count; i++) 9 { 10 MenuItem menuItem = breakfastItems[i] as MenuItem; 11 Console.WriteLine(menuItem.GetName()+" "+menuItem.GetPrice().ToString()+" "+menuItem.GetDescription().ToString()); 12 } 13 //遍历数组 14 for (int j = 0; j < lunchItems.Length; j++) 15 { 16 MenuItem lunchItem = lunchItems[j] ; 17 if (lunchItem!=null) 18 { 19 Console.WriteLine(lunchItem.GetName() + " " + lunchItem.GetPrice().ToString() + " " + lunchItem.GetDescription().ToString()); 20 } 21 } 22 23 Console.ReadKey();
很明显上面的遍历的算法是一样的,因为早餐和晚餐的数据结构的不同导致了代码不能复用,当然可以使用泛型解决该问题。但是本文需要使用的是迭代器设计模式。
使用迭代器:
为了可以使用相同的遍历方法,我们定义一个接口迭代器:
1 public interface Iterator 2 { 3 /// <summary> 4 /// 用来判断下一个元素是否为空 5 /// </summary> 6 /// <returns></returns> 7 bool HasNext(); 8 9 /// <summary> 10 /// 用来获取当前元素 11 /// </summary> 12 /// <returns></returns> 13 object Next(); 14 }
我们希望的是能通过迭代器,使对早餐和晚餐菜单的遍历一次性完成,即实现下面的操作:
1 while (iterator.HasNext()) 2 { 3 MenuItem menuitem = (MenuItem)iterator.Next; 4 Console.WriteLine(menuitem.GetName() + " " + menuitem.GetPrice().ToString() + " " + menuitem.GetDescription().ToString()); 5 6 }
下面创建早晚餐的迭代器:
继承上面的接口并实现hasnext()和next()方法,其中早餐迭代器中的next()方法中取得arraylist的特定菜单项(MenuItem类型),晚餐迭代器中的next()方法取得数组中的特定菜单项(MenuItem类型)。
1 public class BreakfastIterator : Iterator 2 { 3 private ArrayList items; 4 private int position; 5 public BreakfastIterator(ArrayList arrayList) 6 { 7 items = arrayList; 8 } 9 public bool HasNext() 10 { 11 if (position>items.Count||items[position]==null) 12 { 13 return false; 14 } 15 else 16 { 17 return true; 18 } 19 } 20 21 public object Next() 22 { 23 MenuItem menuItem = items[position] as MenuItem; 24 position = position + 1; 25 return menuItem; 26 } 27 }
晚餐迭代器:
1 public class DinnerIterator : Iterator 2 { 3 private MenuItem[] items; 4 private int position = 0; 5 6 public DinnerIterator(MenuItem[] items) 7 { 8 this.items = items; 9 } 10 public bool HasNext() 11 { 12 if (position > items.Length || items[position] == null) 13 { 14 return false; 15 } 16 else 17 { 18 return true; 19 } 20 } 21 22 public object Next() 23 { 24 MenuItem menuItem = items[position] as MenuItem; 25 position = position + 1; 26 return menuItem; 27 } 28 }
为了使用迭代器,那么早餐和晚餐菜单类需要分别创建一个创建迭代器的方法,这个方法可以继承自一个接口。
Imenu接口:
1 public interface IMenu 2 { 3 Iterator CreateIterator(); 4 }
早餐breakfastmenu类继承并实现CreateIterator():
1 public class BreakfastMenu : IMenu 2 { 3 ArrayList menuItems; 4 5 public BreakfastMenu() 6 { 7 menuItems = new ArrayList(); 8 AddItem("牛奶", "牛奶description", false, 3.0); 9 AddItem("油条","油条description",false,1.0); 10 AddItem("馒头","馒头description",true,1.0); 11 AddItem("豆浆", "DoujiangDescription", true, 1.5); 12 } 13 14 public void AddItem(string name, string description, bool vegetarian, double price) 15 { 16 MenuItem menuItem = new MenuItem( name, description, vegetarian, price); 17 menuItems.Add(menuItem); 18 } 19 20 public ArrayList GetMenuItems() 21 { 22 return menuItems; 23 } 24 25 public Iterator CreateIterator() 26 { 27 return new BreakfastIterator(menuItems); 28 } 29 30 31 }
早餐dinnermenu类继承并实现CreateIterator():
1 public class DinnerMenu:IMenu 2 { 3 static readonly int Max_ITEMS = 6; 4 int numberOfItems = 0; 5 MenuItem[] menuItems; 6 7 public DinnerMenu() 8 { 9 menuItems = new MenuItem[Max_ITEMS]; 10 AddItem("香菇豆腐饭", "香菇豆腐", false, 10.5); 11 AddItem("蛋炒饭","哈哈",false,8.5); 12 AddItem("鱼香肉丝","你猜",true,15.5); 13 } 14 15 public void AddItem(string name, string description, bool vegetarian, double price) 16 { 17 MenuItem menuItem = new MenuItem(name, description, vegetarian, price); 18 if (numberOfItems>Max_ITEMS) 19 { 20 Console.WriteLine("菜单已满"); 21 } 22 else 23 { 24 menuItems[numberOfItems] = menuItem; 25 numberOfItems++; 26 } 27 } 28 public MenuItem[] GetMenuItems() 29 { 30 return menuItems; 31 } 32 33 public Iterator CreateIterator() 34 { 35 return new DinnerIterator(menuItems); 36 } 37 }
客户端调用:
1 class Client 2 { 3 static void Main(string[] args) 4 { 5 IMenu breakfastMenu = new BreakfastMenu(); 6 IMenu dinnerMenu = new DinnerMenu(); 7 breakfastMenu.CreateIterator(); 8 Iterator dinnerIterator = dinnerMenu.CreateIterator(); 9 Iterator breakfastIterator = breakfastMenu.CreateIterator(); 10 11 Print(breakfastIterator); 12 Print(dinnerIterator); 13 14 Console.ReadKey(); 15 } 16 17 static void Print(Iterator iterator) 18 { 19 while (iterator.HasNext()) 20 { 21 MenuItem menuItem = (MenuItem)iterator.Next(); 22 Console.WriteLine(menuItem.GetName() + " " + menuItem.GetPrice().ToString() + " " + menuItem.GetDescription().ToString()); 23 } 24 } 25 }
可以看到,上面的迭代器模式一共有:
MenuItem类:菜单项类,早餐和晚餐菜单类有很多菜单项,他们有不同的组织方法(早餐是MenuItem类型的arraylist,晚餐是MenuItem类型的array)
Iterator接口类:定义hasnext()方法和next()方法
BreakfastIterator类:继承Iterator接口,成员是一个arraylist和一个int型的标志位置的游标postion,hasnext()方法判断arryalist中是否有下一个item,next()获取arraylist中的下一个item。
DinnerIterator类:继承Iterator接口,成员是一个 MenuItem类型的数组和一个int型的标志位置的游标postion,hasnext()方法判断数组中是否有下一个item,next()获取数组中的下一个item。
Imenu接口类:定义createIterator()方法
BreakfastMenu类:继承Imenu接口,初始化MenuItem类型的arraylist,GetMenuItems()中返回arraylist,CreateIterator()中初始化早餐类迭代器并返回。
DinnerMenu类:继承Imenu接口,初始化MenuItem类型的数组,GetMenuItems()中返回MenuItem[],CreateIterator()中初始化晚餐类迭代器并返回。
Client类:初始化对象聚合类breakfastmenu和dinnermenu,以及相应的迭代器类breakfastIterator和dinnerIterator
运用迭代模式的前后对比:
没有使用迭代器模式时,只有menuItem,breakfastmenu和dinnermenu,以及client,并且迭代元素的任务是聚合对象(breakfastmenu和dinnermenu)自己完成的。
运用迭代器模式时,迭代元素的任务是迭代器breakfastIterator和dinnerIterator完成的,而不是聚合对象,我们甚至在不需要知道该聚合对象的内部结构就可以实现该聚合对象的迭代。
上面代码的类图:
迭代器模式类图:
参与者:
Iterator: 抽象迭代器:所有迭代器都需要实现的接口,提供了游走聚合对象元素之间的方法。
ConcreteIterator: 具体迭代器。利用这个具体的迭代器能够对具体的聚合对象进行遍历。每一个聚合对象都应该对应一个具体的迭代器。
Aggregate: 抽象聚合类。
ConcreteAggregate: 具体聚合类。实现creatorIterator()方法,返回该聚合对象的迭代器。
迭代器模式主要是聚合对象创建迭代器,借助单一职责的原则,从而实现客户端可以对聚合的各种对象实现相同的操作,达到代码复用的效果。
文章参考:http://www.cnblogs.com/lzhp/p/3427704.html
标签:
原文地址:http://www.cnblogs.com/xfvipp/p/5486003.html