设计模式--迭代器模式
定义:
迭代器模式提供了一种方法顺序访问一个聚合对象中的各个元素,而又不暴露内部的表示
理解:
当访问一个聚合对象(ArrayList,Array)时,不管这些对象是什么时,都需要访问,这样可以考虑迭代器模式.
或者当访问聚合对象有几个不同的方式时,也可以考虑使用迭代器模式
实际上,遍历的行为可以理解为从第一个开始,查看下一个,是否还存在下一个.
设计原则:
单一原则:一个类应该只有一个引起变化的原因
关键词:
Iterator
结构图:
例子:
两个餐厅准备合并销售,一个餐厅负责早餐,一个餐厅负责午饭,但是两个餐厅存储菜单的方式不一致,导致服务员获取菜单后,还得自己进行分析才可以使用.如何能够使服务员不用对两个餐厅的菜单内容进行直接操作呢?现在看直接实现的结果,此结果导致服务员和两个餐厅的菜单相当耦合.
菜单类:
public class DfMenuItem { string name; string description; double price; public DfMenuItem(string name,string description,double price) { this.name = name; this.description = description; this.price = price; } public string GetName() { return this.name; } public string GetDescription() { return this.description; } public double GetPrice() { return this.price; } }早餐菜单类 public class PancakHouseMenu { ArrayList al; public PancakHouseMenu() { al = new ArrayList(); AddItem("Pancak1", "this is cake1", 11.0); AddItem("Pancak2", "this is cake2", 12.0); AddItem("Pancak3", "this is cake3", 13.0); AddItem("Pancak4", "this is cake4", 14.0); } private void AddItem(string name, string description, double price) { DfMenuItem dmi = new DfMenuItem(name, description, price); al.Add(dmi); } public ArrayList GetMenus() { return this.al; } }午餐菜单类: public class DinnerMenu { DfMenuItem[] dmis; int num = 0; public DinnerMenu() { dmis = new DfMenuItem[4]; AddItem("Dinner1", "this is dinner1", 1.0); AddItem("Dinner2", "this is dinner2", 2.0); AddItem("Dinner3", "this is dinner3", 3.0); AddItem("Dinner4", "this is dinner4", 4.0); } private void AddItem(string name, string description, double price) { DfMenuItem item = new DfMenuItem(name, description, price); dmis[num] = item; num = num + 1; } public DfMenuItem[] GetMenus() { return this.dmis; } } ------------------------------------------------------------以上为两个已实现的类,下面是调用的方法:服务员类:public class Waitress { DinnerMenu dinnerMenus; PancakHouseMenu pancakesMenus; public Waitress(DinnerMenu dinnerMenus,PancakHouseMenu pancakesMenus) { // //TODO: 在此处添加构造函数逻辑 // this.dinnerMenus = dinnerMenus; this.pancakesMenus = pancakesMenus; } public void PrintMenu() { PrintBreakFastMenu(); PrintLunchMenu(); } public void PrintBreakFastMenu() { DfMenuItem[] menus = dinnerMenus.GetMenus(); for (int i = 0; i < menus.Length; i++) { HttpContext.Current.Response.Write(menus[i].GetDescription() + "<br/>"); } } public void PrintLunchMenu() { ArrayList panlist = pancakesMenus.GetMenus(); for (int i = 0; i < panlist.Count; i++) { HttpContext.Current.Response.Write(((DfMenuItem)panlist[i]).GetDescription()+"<br/>"); } } }可以看到waitress类需要知道PancakMenus中菜单的实现方式,也需要知道dinnerMenus中菜单的实现方式 --------------------------------------------------------------- protected void Button1_Click(object sender, EventArgs e) { DinnerMenu dinnerMenus = new DinnerMenu(); PancakHouseMenu pancakeMenus = new PancakHouseMenu(); WaiterTress wt = new WaiterTress(dinnerMenus,pancakeMenus); wt.PrintMenu(); } protected void Button2_Click(object sender, EventArgs e) { DinnerMenu dinnerMenus = new DinnerMenu(); PancakHouseMenu pancakeMenus = new PancakHouseMenu(); WaiterTress wt = new WaiterTress(dinnerMenus, pancakeMenus); wt.PrintBreakFastMenu(); } protected void Button3_Click(object sender, EventArgs e) { DinnerMenu dinnerMenus = new DinnerMenu(); PancakHouseMenu pancakeMenus = new PancakHouseMenu(); WaiterTress wt = new WaiterTress(dinnerMenus, pancakeMenus); wt.PrintLunchMenu(); }此例子的缺点:如果再有一个用的存储方式发生变化的话,可能为影响到waitress的实现.修改两个Menu类.实现解耦.不让waitress对两个menu进行直接的实现.
改变之后:
public class DfMenuItem { string name; string description; double price; public DfMenuItem(string name,string description,double price) { this.name = name; this.description = description; this.price = price; } public string GetDescription() { return this.description; } } public class PancakHouseMenu { ArrayList al; public PancakHouseMenu() { al = new ArrayList(); AddItem("Pancak1", "this is cake1", 11.0); AddItem("Pancak2", "this is cake2", 12.0); AddItem("Pancak3", "this is cake3", 13.0); AddItem("Pancak4", "this is cake4", 14.0); } private void AddItem(string name, string description, double price) { DfMenuItem dmi = new DfMenuItem(name, description, price); al.Add(dmi); } public IIterator CreateIterator() { return new PancakeIterator(al); } } public class DinnerMenu { DfMenuItem[] dmis; int num = 0; public DinnerMenu() { dmis = new DfMenuItem[4]; AddItem("Dinner1", "this is dinner1", 1.0); AddItem("Dinner2", "this is dinner2", 2.0); AddItem("Dinner3", "this is dinner3", 3.0); AddItem("Dinner4", "this is dinner4", 4.0); } private void AddItem(string name, string description, double price) { DfMenuItem item = new DfMenuItem(name, description, price); dmis[num] = item; num = num + 1; } public IIterator CreateIterator() { return new DinnerIterator(this.dmis); } } public interface IIterator { bool HasNext(); object Next(); } public class DinnerIterator :IIterator { DfMenuItem[] items; int position = 0; public DinnerIterator(DfMenuItem[] items) { this.items = items; } #region IIterator 成员 public bool HasNext() { if (position >= items.Length) { return false; } return true; } public object Next() { DfMenuItem item = items[position]; position = position + 1; return item; } #endregion } public class PancakeIterator : IIterator { ArrayList al; int position; public PancakeIterator(ArrayList al) { this.al = al; } #region IIterator 成员 public bool HasNext() { if (position >= al.Count) { return false; } return true; } public object Next() { return al[position++]; } #endregion } ----------------------------------------------------------------- public class WaiterTress { DinnerMenu dinnerMenus; PancakHouseMenu pancakesMenus; public WaiterTress(DinnerMenu dinnerMenus, PancakHouseMenu pancakesMenus) { // //TODO: 在此处添加构造函数逻辑 // this.dinnerMenus = dinnerMenus; this.pancakesMenus = pancakesMenus; } public void PrintMenu() { PrintBreakFastMenu(); PrintLunchMenu(); } public void PrintBreakFastMenu() { Print(pancakesMenus.CreateIterator()); } public void PrintLunchMenu() { Print(dinnerMenus.CreateIterator()); } private void Print(IIterator iteraotr) { while (iteraotr.HasNext()) { DfMenuItem item = iteraotr.Next() as DfMenuItem; HttpContext.Current.Response.Write(item.GetDescription() + "<br/>"); } } }
类图:
优点:
客户端不知道服务器端是如何存储数据,只需要调用就可以了.
客户端无需管服务器段的数据存储是否发生变化,只需调用Iterator即可.此时,如果服务器端使用XML,文本,数据库来存储数据,均不会影响到客户端的引用.
参考:
《深入浅出设计模式》
《大话设计模式》