迭代器模式定义:提供一种方法顺序访问一个聚合元素中的各个元素,而又不暴漏该对象的内部表示
来看下面这个场景,客人在餐厅点餐前,首先会浏览餐厅的菜单,菜单使用List存储所有菜单条目
/**
* Created by sean on 2018/7/8.
*/
public class Item {
private String name;
private Float value;
public Item(String name, Float value){
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public Float getValue() {
return value;
}
@Override
public String toString() {
return name + ":" + value;
}
}
import java.util.LinkedList;
import java.util.List;
/**
* Created by sean on 2018/7/8.
*/
public class Menu {
private List<Item> items = new LinkedList<>();
public void addItem(String name, Float value){
Item item = new Item(name, value);
items.add(item);
}
public List<Item> getItems(){
return items;
}
}
import java.util.List;
/**
* Created by sean on 2018/7/8.
*/
public class Customer {
public static void main(String[] args){
Menu menu = new Menu();
menu.addItem("a", 1.1f);
menu.addItem("b", 1.2f);
menu.addItem("c", 1.3f);
List<Item> items = menu.getItems();
for(Item item : items){
System.out.println(item.toString());
}
}
}
出于某种原因需要修改菜单条目的存储结构,此时客人遍历菜单的方式也需要进行修改
import java.util.Map;
import java.util.TreeMap;
/**
* Created by sean on 2018/7/8.
*/
public class Menu {
private Map<String, Item> items = new TreeMap<>();
public void addItem(String name, Float value){
Item item = new Item(name, value);
items.put(name, item);
}
public Map<String, Item> getItems(){
return items;
}
}
import java.util.Map;
/**
* Created by sean on 2018/7/8.
*/
public class Customer {
public static void main(String[] args){
Menu menu = new Menu();
menu.addItem("a", 1.1f);
menu.addItem("b", 1.2f);
menu.addItem("c", 1.3f);
Map<String, Item> items = menu.getItems();
for(Item item : items.values()){
System.out.println(item.toString());
}
}
}
对于客人来说,只要可以遍历菜单即可,并不关系菜单使用何种方式存储其内容
菜单存储其内容的方式发生变化,不应该导致用户遍历菜单的方式发生变化
因此菜单类需要隐藏其内部数据结构的具体实现方式,并对外提供统一的方式供客户浏览菜单内容
/**
* Created by sean on 2018/7/8.
*/
public interface Iterator {
public boolean hasNext();
public Object next();
}
import java.util.*;
/**
* Created by sean on 2018/7/8.
*/
public class Menu implements Iterator {
private Map<String, Item> items = new TreeMap<>();
private int position = 0;
public void addItem(String name, Float value){
Item item = new Item(name, value);
items.put(name, item);
}
@Override
public boolean hasNext() {
if(items.size() > 0 && position < items.size())
return true;
else
return false;
}
@Override
public Object next() {
if(items.size() > 0 && position < items.size()){
List<String> keys = new LinkedList<>();
keys.addAll(items.keySet());
String key = keys.get(position);
Item item = items.get(key);
position++;
return item;
}
return null;
}
}
/**
* Created by sean on 2018/7/8.
*/
public class Customer {
public static void main(String[] args){
Menu menu = new Menu();
menu.addItem("a", 1.1f);
menu.addItem("b", 1.2f);
menu.addItem("c", 1.3f);
while(menu.hasNext()){
System.out.println(menu.next().toString());
}
}
}
考虑如下两个问题:
1 在菜单内部保存了遍历时的序号,而且该序号不会自动重置,因此每个菜单类的实例仅能遍历一次,这在实际开发过程中几乎是不可能的
2 菜单只能按照一种方式进行遍历,如果客人要按照其它规则进行遍历,hasNext方法与next方法的具体实现方式都需要进行修改
因此需要让菜单的存储方式和遍历方式之间解耦,以便它们互不影响
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Created by sean on 2018/7/8.
*/
public class MapIterator implements Iterator {
private Map<String, Item> data = null;
private List<String> keys = new LinkedList<>();
private int position = 0;
public MapIterator(Map<String, Item> data){
this.data = data;
keys.addAll(data.keySet());
}
@Override
public boolean hasNext() {
if(data.size() > 0 && position < data.size())
return true;
else
return false;
}
@Override
public Object next() {
if(data.size() > 0 && position < data.size()){
String key = keys.get(position);
Item item = data.get(key);
position++;
return item;
}
return null;
}
}
/**
* Created by sean on 2018/7/8.
*/
public interface DataStructure {
public Iterator createIterator();
}
import java.util.Map;
import java.util.TreeMap;
/**
* Created by sean on 2018/7/8.
*/
public class Menu implements DataStructure {
private Map<String, Item> items = new TreeMap<>();
public void addItem(String name, Float value){
Item item = new Item(name, value);
items.put(name, item);
}
@Override
public Iterator createIterator() {
MapIterator iterator = new MapIterator(items);
return iterator;
}
}
/**
* Created by sean on 2018/7/8.
*/
public class Customer {
public static void main(String[] args){
Menu menu = new Menu();
menu.addItem("a", 1.1f);
menu.addItem("b", 1.2f);
menu.addItem("c", 1.3f);
Iterator iterator = menu.createIterator();
while(iterator.hasNext())
System.out.println(iterator.next().toString());
}
}
如果我们想换一种遍历方式,没问题,只要实现新的Iterator接口实现类即可,当然此时还是需要修改Menu类的createIterator方法,如果不想修改该方法,我们可以使用简单工厂改造createIterator方法的具体实现方式,使createIterator方法与具体的Iterator接口实现类解耦,这样我们切换遍历方式,仅需修改工厂类即可