设计模式--迭代器模式

定义:

迭代器模式提供了一种方法顺序访问一个聚合对象中的各个元素,而又不暴露内部的表示 

理解:

当访问一个聚合对象(ArrayList,Array)时,不管这些对象是什么时,都需要访问,这样可以考虑迭代器模式.

或者当访问聚合对象有几个不同的方式时,也可以考虑使用迭代器模式

实际上,遍历的行为可以理解为从第一个开始,查看下一个,是否还存在下一个.

设计原则:

单一原则:一个类应该只有一个引起变化的原因

关键词:

 Iterator

结构图:

image  

例子:

两个餐厅准备合并销售,一个餐厅负责早餐,一个餐厅负责午饭,但是两个餐厅存储菜单的方式不一致,导致服务员获取菜单后,还得自己进行分析才可以使用.如何能够使服务员不用对两个餐厅的菜单内容进行直接操作呢?现在看直接实现的结果,此结果导致服务员和两个餐厅的菜单相当耦合.

菜单类:

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/>");
        }
    }
}
类图:
image 

优点:

 客户端不知道服务器端是如何存储数据,只需要调用就可以了.

客户端无需管服务器段的数据存储是否发生变化,只需调用Iterator即可.此时,如果服务器端使用XML,文本,数据库来存储数据,均不会影响到客户端的引用.

参考:

《深入浅出设计模式》

《大话设计模式》

posted @ 2009-08-27 17:09  Localhost  阅读(283)  评论(0编辑  收藏  举报