迭代器模式
为什么会有迭代器模式
我们在对对象元素进行处理时,有时需要将同一类对象堆起来成为一个集合,集合的数据类型可以是数组、栈、列表、HashMap等数据类型;但在某些时候,你的客户想要遍历这些对象,出于数据安全,你又不想让用户知道存储对象元素的集合的数据类型,迭代器的作用就是能让客户遍历你的对象,而又无法窥视你是如何(存储对象元素的集合数据类型客户不知道)存储对象的。
没有使用迭代器的代码设计
对象村餐厅和对象寸煎饼屋合并
餐厅对象和煎饼屋对象共用的菜单项类
public class MenuItem {
String name;
String description;
double price;
public MenuItem(String name, String description, double price) {
this.name = name;
this.description = description;
this.price = price;
}
public String getName() {...}
public void setName(String name) {...}
public String getDescription() {...}
public void setDescription(String description) {...}
public double getPrice() {...}
public void setPrice(double price) {...}
@Override
public String toString() {...}
}
餐厅菜单对象
//餐厅菜单实现
public class DinerMenu {
int numberOfItems=0;
MenuItem[] menuItems;
static final int MAX_ITEMS=6;
public DinerMenu(){
menuItems = new MenuItem[MAX_ITEMS];
addItem("BLT","Bacon with lettuce",2.99);
addItem("Vegetarian BLT","Bacon with tomato",2.99);
addItem("Hotdog","A hot dog,with sauerkraut",2.99);
}
public void addItem(String name,String description,Double price){
MenuItem menuItem = new MenuItem(name,description,price);
if(numberOfItems >= MAX_ITEMS){
System.out.println("error");
}else{
menuItems[numberOfItems] = menuItem;
numberOfItems++;
}
}
public MenuItem[] getMenuItems(){
return menuItems;
}
}
煎饼屋菜单对象
//煎饼屋菜单实现
public class PancakeHouseMenu {
ArrayList<MenuItem> menuItems = new ArrayList<MenuItem>();;
public PancakeHouseMenu() {
addItem("A Pancake Breakfase","Pancakes whith eggs ang toast",2.99);
addItem("A Pancake Breakfase","Pancakes whith eggs ang toast",2.99);
addItem("A Pancake Breakfase","Pancakes whith eggs ang toast",2.99);
}
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;
}
}
创建一个Java版本的女招待,女招待能按需为顾客打印定制的菜单
//女招待
public class Alice {
void printMenu(){
//获得煎饼屋菜单对象
PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
//获得煎饼屋对象中的菜单列表
ArrayList<MenuItem> menuItems = pancakeHouseMenu.getMenuItems();
//遍历菜单列表
for(int i=0;i<menuItems.size();i++) {
MenuItem menuItem = menuItems.get(i);
System.out.println(menuItem.getName() + " ");
System.out.println(menuItem.getDescription()+ " ");
System.out.println(menuItem.getPrice()+ " ");
}
//获得餐厅菜单对象
DinerMenu dinerMenu = new DinerMenu();
//获得餐厅菜单对象中的菜单数组
MenuItem[] menuItems1 = dinerMenu.getMenuItems();
//遍历菜单数组
for(int i=0;i<menuItems1.length;i++){
MenuItem menuItem = menuItems1[i];
System.out.println(menuItem.getName()+" ");
System.out.println(menuItem.getDescription()+" ");
System.out.println(menuItem.getPrice()+" ");
}
}
}
为了打印菜单我们需要遍历两个不同的集合。
使用了自定义迭代器的代码设计
迭代器接口
//迭代器接口
public interface Iterator {
boolean hasNext();
MenuItem next();
}
煎饼屋菜单列表迭代器
//煎饼屋菜单列表迭代器
public class PancakeHouseIterator implements Iterator {
ArrayList<MenuItem> items;
int count = 0;
public PancakeHouseIterator(ArrayList<MenuItem> menuItems){
this.items=menuItems;
}
public boolean hasNext(){
if(count >= items.size() || items.get(count)==null)
return false;
else
return true;
}
public MenuItem next(){
MenuItem menuItem = items.get(count);
count++;
return menuItem;
}
}
//煎饼屋菜单实现
public class PancakeHouseMenu {
ArrayList<MenuItem> menuItems = new ArrayList<MenuItem>();;
public PancakeHouseMenu() {
addItem("A Pancake Breakfase","Pancakes whith eggs ang toast",2.99);
addItem("A Pancake Breakfase","Pancakes whith eggs ang toast",2.99);
addItem("A Pancake Breakfase","Pancakes whith eggs ang toast",2.99);
}
public void addItem(String name,String description,double price){
MenuItem menuItem = new MenuItem(name, description, price);
menuItems.add(menuItem);
}
public Iterator createrIterator(){
return new PancakeHouseIterator(menuItems);
}
}
餐厅菜单迭代器
//餐厅菜单迭代器
public class DinerMenuIterator implements Iterator{
MenuItem[] menuItems;
int position = 0;
public DinerMenuIterator(MenuItem[] menuItems){
menuItems = menuItems;
}
public boolean hasNext(){
if(position >= menuItems.length || menuItems[position] == null)
return false;
else
return true;
}
public MenuItem next(){
MenuItem menuItem = menuItems[position];
position++;
return menuItem;
}
}
//餐厅菜单实现
public class DinerMenu {
int numberOfItems=0;
MenuItem[] menuItems;
public DinerMenu(){
addItem("BLT","Bacon with lettuce",2.99);
addItem("Vegetarian BLT","Bacon with tomato",2.99);
addItem("Hotdog","A hot dog,with sauerkraut",2.99);
}
public void addItem(String name,String description,Double price){
MenuItem menuItem = new MenuItem(name,description,price);
menuItems[numberOfItems] = menuItem;
numberOfItems++;
}
public Iterator createIterator(){
return new DinerMenuIterator(menuItems);
}
}
//使用迭代器的女招待
public class Alice {
PancakeHouseMenu pancakeHouseMenu;
Iterator menuItems;
void printMenu(){
//获得煎饼屋菜单对象
pancakeHouseMenu = new PancakeHouseMenu();
//获得煎饼屋对象中的菜单迭代器
menuItems = pancakeHouseMenu.createrIterator();
//获得餐厅菜单对象
DinerMenu dinerMenu = new DinerMenu();
//获得餐厅菜单对象中的菜单迭代器
Iterator menuItems1 = dinerMenu.createIterator();
}
void printMenu(Iterator iterator){
while(iterator.hasNext()){
MenuItem menuItem = iterator.next();
System.out.println(menuItem.getName() + " ");
System.out.println(menuItem.getDescription()+ " ");
System.out.println(menuItem.getPrice()+ " ");
}
}
}
现在菜单的实现被封装,女招待不知道菜单如何持有菜单项的集合;只要实现迭代器,我们只需要一个循环,就可以多态的处理任何项的集合;由原先的捆绑道具体类(MenuITtem[]和ArrayList),到现在只需要使用一个Iterator接口,使程序变得更具维护和扩展。
唯一不足的是女招待仍然绑定到具体的菜单类(PancakeHouseMenu和DinerMenu).
使用Java提供的Iterator进行优化
为PancakeHouseMenu和DinerMenu提供应该公共接口Menu
public interface Menu {
Iterator<MenuItem> createIterator();
}
PancakeHouseIterator和DinerIterator实现java提供的迭代器接口(不用在自定义Iterator)
public class PancakeHouseIterator implements Iterator {
//内容不变
}
public class DinerMenuIterator implements Iterator {
//内容不变
}
PancakeHouseMenu和DinerMenu
//煎饼屋菜单实现
public class PancakeHouseMenu implements Menu {
//内容不变
//java自带的迭代器需要声明泛型
public Iterator<MenuItem> createIterator(){
return new PancakeHouseIterator(menuItems);
}
}
//餐厅菜单实现
public class DinerMenu implements Menu {
//内容不变
//java自带的迭代器需要声明泛型
public Iterator<MenuItem> createIterator(){
return new DinerMenuIterator(menuItems);
}
}
Alice
//使用迭代器的女招待
public class Alice {
Menu pancakeHouseMenu;
Menu dinerMenu;
public Alice(Menu pancakeHouseMenu,Menu dinerMenu){
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
}
void printMenu(){
//获得煎饼屋菜单对象
pancakeHouseMenu = new PancakeHouseMenu();
//获得煎饼屋对象中的菜单迭代器
Iterator menuItems = pancakeHouseMenu.createIterator();
printMenu(menuItems);
//获得餐厅菜单对象
dinerMenu = new DinerMenu();
//获得餐厅菜单对象中的菜单迭代器
Iterator menuItems1 = dinerMenu.createIterator();
printMenu(menuItems1);
}
void printMenu(Iterator<MenuItem> iterator){
while(iterator.hasNext()){
MenuItem menuItem = iterator.next();
System.out.println(menuItem.getName() + " ");
System.out.println(menuItem.getDescription()+ " ");
System.out.println(menuItem.getPrice()+ " ");
}
}
}
测试
public class MenuTestDrive {
public static void main(String[] args) {
PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
DinerMenu dinerMenu = new DinerMenu();
Alice alice = new Alice(pancakeHouseMenu,dinerMenu);
alice.printMenu();
}
}
迭代器类图
迭代器模式作用
迭代器模式让我们变了聚合元素,而不暴露器潜在实现;同时迭代器拿走了遍历元素的责任,把它交给迭代器对象而不是聚合对象,使得聚合对象的职责更加明确,使其专注于管理对象集合,简化了聚合的接口和实现。