迭代器模式 (行为型)

迭代器模式(Iterator Pattern)是 Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。

迭代器模式属于行为型模式。

介绍

意图:提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。

主要解决:不同的方式来遍历整个整合对象。

何时使用:遍历一个聚合对象。

如何解决:把在元素之间游走的责任交给迭代器,而不是聚合对象。

关键代码:定义接口:hasNext, next。

应用实例:JAVA 中的 iterator。

优点: 1、它支持以不同的方式遍历一个聚合对象。 2、迭代器简化了聚合类。 3、在同一个聚合上可以有多个遍历。 4、在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。

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

使用场景: 1、访问一个聚合对象的内容而无须暴露它的内部表示。 2、需要为聚合对象提供多种遍历方式。 3、为遍历不同的聚合结构提供一个统一的接口。

注意事项:迭代器模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。


demo

定义一个菜单项类,里面有菜单价格、名字、描述属性,

有两个餐厅DinerMenu和pancakeHourseMenu 它们可以添加菜单项,得到菜单集合

女服务员Waitress,负责根据不同的餐厅打印出他们的菜单集合

定义一个菜单接口

package menu;

import item.MenuItem;

public interface Menu
{
     /**
      * 添加菜单项
      * @param name
      * @param description
      * @param price
      */
     void addItem(String name, String description, double price);

     /**
      * 获取菜单项集合
      */
     Object getMenuItems();
}

定义一个菜单项类

package item;

/**
 * 菜单项
 */
public class MenuItem
{
	private String name;              //菜单项名称
	private String description;       //描述
	private double price;             //价格
 
	public MenuItem(String name,
                    String description,
                    double price)
	{
		this.name = name;
		this.description = description;
		this.price = price;
	}

	public String toString()
	{
		return (name + ": "+description+", $" + price);
	}
}

定义两个餐厅类,他们实现了菜单接口

package menu;

import item.MenuItem;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * 煎饼屋餐厅
 */
public class PancakeHouseMenu implements Menu
{
	private ArrayList<MenuItem> menuItems;
 
	public PancakeHouseMenu()
	{
		menuItems = new ArrayList();
    
		addItem("薄煎饼早餐",
			"薄煎饼、鸡蛋和土司",
			2.99);
 
		addItem("蓝莓薄煎饼",
			"新鲜蓝莓和蓝莓果酱做成的薄煎饼",
			2.99);
 
		addItem("松饼",
			"松饼,可以选择蓝莓或者草莓口味",
			3.59);
	}

	public void addItem(String name, String description, double price)
	{
		MenuItem menuItem = new MenuItem(name, description, price);
		menuItems.add(menuItem);
	}


	public ArrayList<MenuItem> getMenuItems()
	{
		return menuItems;
	}

}
package menu;

import item.MenuItem;
import iterator.DinerMenuIterator;
import java.util.Iterator;

/**
 * 对象村餐厅
 */
public class DinerMenu implements Menu
{
    private static final int MAX_ITEMS = 4;
    private int numberOfItems = 0;
    private MenuItem[] menuItems;
  
	public DinerMenu() {
		menuItems = new MenuItem[MAX_ITEMS];
 
		addItem("素食 BLT", "(煎)培根, 生菜和西红柿",  2.99);
		addItem("清汤", "一碗清汤, 配土豆沙拉", 3.29);
		addItem("热狗", "一个热狗, 酸菜, 芝士, 洋葱",  3.05);
		addItem("清蒸时蔬加糙米", "清蒸的蔬菜配糙米", 3.99);
	}
  
	public void addItem(String name, String description, double price)
	{
		MenuItem menuItem = new MenuItem(name, description,  price);
		if (numberOfItems >= MAX_ITEMS)
		{
			System.err.println("抱歉, 菜单已满! 不能添加菜单项");
		}
		else
		{
			menuItems[numberOfItems] = menuItem;
			numberOfItems = numberOfItems + 1;
		}
	}

	public MenuItem[] getMenuItems()
	{
		return menuItems;
	}

}

定义一个服务员,它可以根据餐厅名上菜单

import item.MenuItem;
import menu.DinerMenu;
import menu.PancakeHouseMenu;

import java.util.ArrayList;

/**
 * 服务员类,根据餐厅打印菜单
 */
public class Waitress
{
	private PancakeHouseMenu pancakeHouseMenu;
	private DinerMenu dinerMenu;

	public Waitress(PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu) {
		this.pancakeHouseMenu = pancakeHouseMenu;
		this.dinerMenu = dinerMenu;
	}

	/**
	 * 打印煎饼屋菜单
	 */
	public void printPancakeHouseMenu() {
		ArrayList<MenuItem> pancakeHouseItems = pancakeHouseMenu.getMenuItems();

		for (int i = 0; i < pancakeHouseItems.size(); i++)
		{
			MenuItem menuItem = pancakeHouseItems.get(i);
			System.out.println(menuItem);
		}
		System.out.println("\n");
	}

	/**
	 * 打印餐厅村菜单
	 */
	public void printdinerMenu() {
		MenuItem[] menuItems = dinerMenu.getMenuItems();

		for (int i = 0; i < menuItems.length; i++)
		{
			MenuItem menuItem = menuItems[i];
			System.out.println(menuItem);
		}
		System.out.println("\n");
	}
}

测试类

import menu.DinerMenu;
import menu.PancakeHouseMenu;

public class Test
{
    public static void main(String[] args)
    {
        PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
        DinerMenu dinerMenu = new DinerMenu();

        Waitress waitress=new Waitress(pancakeHouseMenu,dinerMenu);

        System.out.println("煎饼屋餐厅菜单------------------------");
        waitress.printPancakeHouseMenu();

        System.out.println("对象村餐厅菜单-------------------------");
        waitress.printdinerMenu();
    }
}

从以上例子可以看出,服务员中的打印菜单方法要遍历每个餐厅的菜单,非常麻烦,首先服务员的属性中必须是两个具体的餐厅类型,而且在遍历时由于每个餐厅里面的菜单项集合类型不同,则遍历时候的操作也不一样,如果再增加一个餐厅和它的菜单类型,则就需要第三种循环方法

思考:如果我们能找打一个方法,让每个餐厅的菜单项都实现一个相同的接口,而不改变菜单项的集合类型,这样就可以最小化招待员代码中的具体引用,同时还可以摆脱遍历这两个菜单所需的多个循环,让招待员和餐厅解耦,把集合的操作交给迭代器

首先上类图

步骤:我们先创建一个迭代器

package iterator;

import item.MenuItem;

/**
 * 自定义一个迭代器接口
 */
public interface Iterator<E>
{
    boolean hasNext();
    MenuItem next();
}

现在我们需要为每个餐厅添加他们自己的迭代器

package iterator;

import item.MenuItem;

public class DinerMenuIterator implements Iterator
{
    private MenuItem[] menuItems;
    private int position = 0;

    public DinerMenuIterator(MenuItem[] menuItems)
    {
        this.menuItems = menuItems;
    }

    @Override
    public boolean hasNext()
    {
        if (position >= menuItems.length || menuItems[position] == null)
            return false;
        else
            return true;
    }

    @Override
    public MenuItem next()
    {
        MenuItem menuItem = menuItems[position++];
        return menuItem;
    }
}
package iterator;

import item.MenuItem;

import java.util.ArrayList;

public class PancakeHouseMenuIterator implements Iterator
{
	ArrayList<MenuItem> items;
	int position = 0;
 
	public PancakeHouseMenuIterator(ArrayList<MenuItem> items)
	{
		this.items = items;
	}
 
	public MenuItem next()
	{
		MenuItem item = items.get(position);
		position = position + 1;
		return item;
	}
 
	public boolean hasNext()
	{
		if (position >= items.size())
			return false;
		 else
			return true;
	}
}

接着在每个餐厅中增加一个createIterator()方法

package menu;

import item.MenuItem;
import iterator.PancakeHouseMenuIterator;

import java.util.ArrayList;
import iterator.Iterator;

/**
 * 煎饼屋餐厅
 */
public class PancakeHouseMenu implements Menu
{
	private ArrayList<MenuItem> menuItems;
 
	public PancakeHouseMenu()
	{
		menuItems = new ArrayList();
    
		addItem("薄煎饼早餐",
			"薄煎饼、鸡蛋和土司",
			2.99);
 
		addItem("蓝莓薄煎饼",
			"新鲜蓝莓和蓝莓果酱做成的薄煎饼",
			2.99);
 
		addItem("松饼",
			"松饼,可以选择蓝莓或者草莓口味",
			3.59);
	}

	public void addItem(String name, String description, double price)
	{
		MenuItem menuItem = new MenuItem(name, description, price);
		menuItems.add(menuItem);
	}


	public ArrayList<MenuItem> getMenuItems()
	{
		return menuItems;
	}

	public Iterator<MenuItem> createIterator() {
		return  new PancakeHouseMenuIterator(menuItems);
	}
}
package menu;

import item.MenuItem;
import iterator.DinerMenuIterator;
import iterator.Iterator;

/**
 * 对象村餐厅
 */
public class DinerMenu implements Menu
{
    private static final int MAX_ITEMS = 4;
    private int numberOfItems = 0;
    private MenuItem[] menuItems;
  
	public DinerMenu() {
		menuItems = new MenuItem[MAX_ITEMS];
 
		addItem("素食 BLT", "(煎)培根, 生菜和西红柿",  2.99);
		addItem("清汤", "一碗清汤, 配土豆沙拉", 3.29);
		addItem("热狗", "一个热狗, 酸菜, 芝士, 洋葱",  3.05);
		addItem("清蒸时蔬加糙米", "清蒸的蔬菜配糙米", 3.99);
	}
  
	public void addItem(String name, String description, double price)
	{
		MenuItem menuItem = new MenuItem(name, description,  price);
		if (numberOfItems >= MAX_ITEMS)
		{
			System.err.println("抱歉, 菜单已满! 不能添加菜单项");
		}
		else
		{
			menuItems[numberOfItems] = menuItem;
			numberOfItems = numberOfItems + 1;
		}
	}

	public MenuItem[] getMenuItems()
	{
		return menuItems;
	}

	@Override
	public Iterator<MenuItem> createIterator() {
		return new DinerMenuIterator(menuItems);
	}


}

在次修改服务员类

import item.MenuItem;
import menu.DinerMenu;
import menu.PancakeHouseMenu;

import java.util.ArrayList;
import iterator.Iterator;

/**
 * 服务员类,根据餐厅打印菜单
 */
public class Waitress
{
	private PancakeHouseMenu pancakeHouseMenu;
	private DinerMenu dinerMenu;

	public Waitress(PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu) {
		this.pancakeHouseMenu = pancakeHouseMenu;
		this.dinerMenu = dinerMenu;
	}

	/**
	 * 打印煎饼屋菜单
	 */
	public void printPancakeHouseMenu() {
		ArrayList<MenuItem> pancakeHouseItems = pancakeHouseMenu.getMenuItems();

		for (int i = 0; i < pancakeHouseItems.size(); i++)
		{
			MenuItem menuItem = pancakeHouseItems.get(i);
			System.out.println(menuItem);
		}
		System.out.println("\n");
	}

	/**
	 * 打印餐厅村菜单
	 */
	public void printdinerMenu() {
		MenuItem[] menuItems = dinerMenu.getMenuItems();

		for (int i = 0; i < menuItems.length; i++)
		{
			MenuItem menuItem = menuItems[i];
			System.out.println(menuItem);
		}
		System.out.println("\n");
	}


	public void printMenu() {
		Iterator pancakeIterator = pancakeHouseMenu.createIterator();
		Iterator dinerIterator = dinerMenu.createIterator();
		printMenu(pancakeIterator);
		printMenu(dinerIterator);

	}

	private void printMenu(Iterator iterator) {
		while (iterator.hasNext()) {
			MenuItem menuItem = iterator.next();
			System.out.println(menuItem);
		}
	}
}

最后的测试类

import menu.DinerMenu;
import menu.PancakeHouseMenu;

public class Test
{
    public static void main(String[] args)
    {
        PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
        DinerMenu dinerMenu = new DinerMenu();

        Waitress waitress=new Waitress(pancakeHouseMenu,dinerMenu);
        waitress.printMenu();
    }
}

运行 结果一样

发布了138 篇原创文章 · 获赞 34 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/bbj12345678/article/details/105158838