迭代器模式(Iterator Pattern)

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

来看下面这个场景,客人在餐厅点餐前,首先会浏览餐厅的菜单,菜单使用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接口实现类解耦,这样我们切换遍历方式,仅需修改工厂类即可


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值