迭代器模式Iterator

迭代器用途:遍历每一个含有的元素

为什么需要迭代器

由于数据结构导致了不同结构数据不一致,相应的操作也有差异
这里写图片描述

  • 例如,数组遍历
        int[] ints = {1, 2, 3};
        if (ints != null) {
            for (int i = 0; i < ints.length; i++) {
                System.out.println(ints[i]);
            }
        }
  • 例如,链表遍历
        List<String> lists = new ArrayList<>();
        lists.add("a");
        lists.add("b");
        lists.add("c");
        if (lists != null) {
            for (int i = 0; i < lists.size(); i++) {
                String temp = lists.get(i);
                System.out.println(temp);
            }
        }
  • 例如,键值对遍历
        Map<String, String> map = new HashMap<>();
        map.put("a", "A");
        map.put("b", "B");
        map.put("c", "C");
        if (map != null) {
            //键稽核
            Set<String> sets = map.keySet();

            //这里使用for循环方式不合适,因为数组与List都可以使用这个,主要是没有其他合适方法输出Set集合
            for (String key : sets) {
                String value = map.get(key);
                System.out.println("key: " + key + ", value:" + value);
            }
        }

测试结果

1
2
3
a
b
c
key: a, value:A
key: b, value:B
key: c, value:C

由上导致的问题

  1. 必须要了解所遍历的对象数据结构,不然无法得知如何遍历
  2. 在编写遍历时候,各种数据结构代码都不一样,不能复用

解决方法,抽象一层遍历接口

这里写图片描述

具体的例子演进

当前开了两家吃饭的店,一家卖早餐,一家卖午餐,他们都有自己的菜单和服务员

食品项

package headfirst.hd.iterator.eg2;

public class Item {

    private String name;
    private float price;

    public Item(String name, float price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String toString() {
        return "[商品名=" + name + ", 价格=" + price + "]";
    }

}

早餐店的菜单,采用数组结构存储

package headfirst.hd.iterator.eg2;

//早餐店品种较少,且种类变化不大,用数组实现
public class BreakfastMenu {
    static final int MAX = 5;

    // 使用数组形式
    private Item[] items;
    int index = 0;

    public BreakfastMenu() {
        items = new Item[MAX];

        addItem("包子", 1.5f);
        addItem("豆浆", 2.00f);
        addItem("油条", 0.99f);
        addItem("大饼", 2.5f);
        addItem("小笼包", 1f);
    }

    public void addItem(String name, float price) {
        Item item = new Item(name, price);
        if (index >= MAX) {
            System.err.println("菜单已经满了,不能添加新种类了");
        } else {
            items[index] = item;
            index = index + 1;
        }
    }

    public Item[] getMenuItems() {
        return items;
    }

}

早餐店的服务员展示菜单

package headfirst.hd.iterator.eg2;

public class WaitressBreakfast {

    private BreakfastMenu menu;

    public WaitressBreakfast(BreakfastMenu menu) {
        this.menu = menu;
    }

    public void printMenus() {
        Item[] menuItems = menu.getMenuItems();
        //进行遍历
        for (int i = 0; i < menuItems.length; i++) {
            Item item = menuItems[i];
            System.out.println(item);
        }
    }
}

测试

package headfirst.hd.iterator.eg2;

public class Client {

    public static void main(String[] args) {

        BreakfastMenu breakfastMenu = new BreakfastMenu();
        WaitressBreakfast breakfast = new WaitressBreakfast(breakfastMenu);
        breakfast.printMenus();

    }

}

测试结果

[商品名=包子, 价格=1.5]
[商品名=豆浆, 价格=2.0]
[商品名=油条, 价格=0.99]
[商品名=大饼, 价格=2.5]
[商品名=小笼包, 价格=1.0]

午餐店的菜单,采用链表结构存储

package headfirst.hd.iterator.eg2;

import java.util.ArrayList;
import java.util.List;

//午餐品种较多,经常添加新品种,用List数据结构
public class LunchMenu {

    private List<Item> items = new ArrayList<>();

    public LunchMenu() {
        addItem("鸡", 15f);
        addItem("鸭", 20f);
        addItem("牛", 29f);
        addItem("羊", 25f);
        addItem("蛋炒", 10f);
        addItem("笋", 12f);
        addItem("其他1", 13f);
        addItem("其他2", 15f);
        addItem("其他3", 18f);
    }

    public void addItem(String name, float price) {
        Item item = new Item(name, price);
        items.add(item);
    }

    public List<Item> getMenuItems() {
        return items;
    }

}

服务员代码

package headfirst.hd.iterator.eg2;

import java.util.List;

public class WaitressLauch {

    private LunchMenu menu;

    public WaitressLauch(LunchMenu menu) {
        this.menu = menu;
    }

    public void printMenus() {
        List<Item> menuItems = menu.getMenuItems();
        //进行遍历
        for (int i = 0; i < menuItems.size(); i++) {
            Item item = menuItems.get(i);
            System.out.println(item);
        }
    }
}

测试代码

package headfirst.hd.iterator.eg2;

public class Client {

    public static void main(String[] args) {    
        LunchMenu lunchMenu = new LunchMenu();
        WaitressLauch lauch = new WaitressLauch(lunchMenu);
        lauch.printMenus();
    }

}

测试结果

[商品名=鸡, 价格=15.0]
[商品名=鸭, 价格=20.0]
[商品名=牛, 价格=29.0]
[商品名=羊, 价格=25.0]
[商品名=蛋炒, 价格=10.0]
[商品名=笋, 价格=12.0]
[商品名=其他1, 价格=13.0]
[商品名=其他2, 价格=15.0]
[商品名=其他3, 价格=18.0]

早餐店和午餐店合并了

问题:只需要一个服务员,但是早餐店的服务员只知道数据结构的实现,午餐店的服务员只知道链表结构的实现,现在又只想雇佣其中一家的服务员,但是又不想修改原有的数据结构先关的代码

原两家店模型设计

这里写图片描述

合并后模型-错误

这里写图片描述

服务员现在要清楚两个不同模型的遍历了,但是原服务员只知道一家的数据结构,最好的办法是屏蔽到数据结构细节,只需要遍历就行了(迭代器思想)

修改模型设计,引入适配器模式达到迭代目标

适配器模式入门:https://blog.csdn.net/dengjili/article/details/79485034

这里写图片描述

对应步骤:

  1. 定义通用访问接口Iterator
  2. 将BreakfastMenu通过BreakfastMenuIterator适配器转换接口为Iterator
  3. 将LunchMenu通过LunchMenuIterator适配器转换接口为Iterator
  4. Waitress只访问Iterator,目的是与具体的数据结构解耦
对应修改代码

新增接口

package headfirst.hd.iterator.eg2;

public interface Iterator<T> {
    T next();
    boolean hasNext();
}

新增适配器

package headfirst.hd.iterator.eg2;

//转换数据结构
public class BreakfastMenuIterator implements Iterator<Item> {

    private Item[] items;
    private int index = 0;

    public BreakfastMenuIterator(Item[] items) {
        this.items = items;
    }

    @Override
    public Item next() {
        Item item = items[index];
        index = index + 1;
        return item;
    }

    @Override
    public boolean hasNext() {
        //传入空对象
        if (items == null) {
            return false;
        }
        //读取到数组尾部
        if (index >= items.length) {
            return false;
        }
        //没初始化对应的值
        if (items[index] ==null) {
            return false;
        }

        return true;
    }

}
package headfirst.hd.iterator.eg2;

import java.util.List;

//转换数据结构
public class LunchMenuIterator implements Iterator<Item>{

    private List<Item> items;
    private int index = 0;

    public LunchMenuIterator(List<Item> items) {
        this.items = items;
    }

    @Override
    public Item next() {
        Item item = items.get(index);
        index = index + 1;
        return item;
    }

    @Override
    public boolean hasNext() {
        //传入空对象
        if (items == null) {
            return false;
        }
        //读取到数组尾部
        if (index >= items.size()) {
            return false;
        }
        //没初始化对应的值
        if (items.get(index) ==null) {
            return false;
        }

        return true;
    }

}

一个服务员

package headfirst.hd.iterator.eg2;

public class Waitress {

    //不清楚是哪一种数据结构
    public void printMenus(Iterator<? extends Item> iterator) {

        //进行遍历
        while (iterator.hasNext()) {
            Item item = iterator.next();
            System.out.println(item);
        }

    }

}

测试代码

package headfirst.hd.iterator.eg2;

public class Client {

    public static void main(String[] args) {
        //两份菜单,通过这种方式可以是任意多菜单和任意数据结构
        BreakfastMenu breakfastMenu = new BreakfastMenu();
        LunchMenu lunchMenu = new LunchMenu();
        //一个服务员
        Waitress waitress = new Waitress();

        System.out.println("打印早餐:");
        //通过适配器
        waitress.printMenus(new BreakfastMenuIterator(breakfastMenu.getMenuItems()));
        System.out.println("打印午餐:");
        //通过适配器
        waitress.printMenus(new LunchMenuIterator(lunchMenu.getMenuItems()));

    }

}

测试结果

打印早餐:
[商品名=包子, 价格=1.5]
[商品名=豆浆, 价格=2.0]
[商品名=油条, 价格=0.99]
[商品名=大饼, 价格=2.5]
[商品名=小笼包, 价格=1.0]
打印午餐:
[商品名=鸡, 价格=15.0]
[商品名=鸭, 价格=20.0]
[商品名=牛, 价格=29.0]
[商品名=羊, 价格=25.0]
[商品名=蛋炒, 价格=10.0]
[商品名=笋, 价格=12.0]
[商品名=其他1, 价格=13.0]
[商品名=其他2, 价格=15.0]
[商品名=其他3, 价格=18.0]

达到预期结果

完善模型设计,达到最终迭代器模式

这里写图片描述

  • 橘黄色为我们平时使用的集合

对应修改代码

package headfirst.hd.iterator.eg2;

//早餐店品种较少,且种类变化不大,用数组实现
public class BreakfastMenu {
    static final int MAX = 5;

    // 使用数组形式
    private Item[] items;
    int index = 0;

    public BreakfastMenu() {
        items = new Item[MAX];

        addItem("包子", 1.5f);
        addItem("豆浆", 2.00f);
        addItem("油条", 0.99f);
        addItem("大饼", 2.5f);
        addItem("小笼包", 1f);
    }

    public void addItem(String name, float price) {
        Item item = new Item(name, price);
        if (index >= MAX) {
            System.err.println("菜单已经满了,不能添加新种类了");
        } else {
            items[index] = item;
            index = index + 1;
        }
    }

    public Iterator<Item> createIterator() {
        return new BreakfastMenuIterator(items);
    }
}
package headfirst.hd.iterator.eg2;

import java.util.ArrayList;
import java.util.List;

//午餐品种较多,经常添加新品种,用List数据结构
public class LunchMenu {

    private List<Item> items = new ArrayList<>();

    public LunchMenu() {
        addItem("鸡", 15f);
        addItem("鸭", 20f);
        addItem("牛", 29f);
        addItem("羊", 25f);
        addItem("蛋炒", 10f);
        addItem("笋", 12f);
        addItem("其他1", 13f);
        addItem("其他2", 15f);
        addItem("其他3", 18f);
    }

    public void addItem(String name, float price) {
        Item item = new Item(name, price);
        items.add(item);
    }

    public Iterator<Item> createIterator() {
        return new LunchMenuIterator(items);
    }

}

测试代码

package headfirst.hd.iterator.eg2;

public class Client {

    public static void main(String[] args) {

        //两份菜单,相当于我们平时用的集合
        BreakfastMenu breakfastMenu = new BreakfastMenu();
        LunchMenu lunchMenu = new LunchMenu();
        //一个服务员
        Waitress waitress = new Waitress();

        System.out.println("打印早餐:");
        //通过适配器
        waitress.printMenus(breakfastMenu.createIterator());
        System.out.println("打印午餐:");
        //通过适配器
        waitress.printMenus(lunchMenu.createIterator());

        //上述代码像我们平时用的代码
        //List<Item> list = new ArrayList<>();
        //list.iterator();

    }

}

java的迭代器和集合

java也有一个Iterator接口,和我们上面例子一致,这里不多讲

主要讲解for/in语句

int[] ints = {1, 2, 3};
        for (int i : ints) {
            System.out.println(i);
        }

        List<String> lists = new ArrayList<>();
        lists.add("a");
        lists.add("b");
        lists.add("c");
        for (String s : lists) {
            System.out.println(s);
        }

        Map<String, String> map = new HashMap<>();
        map.put("a", "A");
        map.put("b", "B");
        map.put("c", "C");
        if (map != null) {
            //键稽核
            Set<String> sets = map.keySet();

            //这里使用for循环方式不合适,因为数组与List都可以使用这个,主要是没有其他合适方法输出Set集合
            for (String key : sets) {
                String value = map.get(key);
                System.out.println("key: " + key + ", value:" + value);
            }
        }

主要思想为迭代器

多个Iterator的整合应用

对应链接:https://blog.csdn.net/dengjili/article/details/79720730

猜你喜欢

转载自blog.csdn.net/dengjili/article/details/79666954