您的位置:首页 > 其它

迭代器模式Iterator

2018-03-23 14:18 155 查看
迭代器用途:遍历每一个含有的元素

为什么需要迭代器

由于数据结构导致了不同结构数据不一致,相应的操作也有差异



例如,数组遍历

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


由上导致的问题

必须要了解所遍历的对象数据结构,不然无法得知如何遍历

在编写遍历时候,各种数据结构代码都不一样,不能复用

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



具体的例子演进

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

食品项

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]
[商品名=小笼包
106a6
, 价格=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



对应步骤:

定义通用访问接口Iterator

将BreakfastMenu通过BreakfastMenuIterator适配器转换接口为Iterator

将LunchMenu通过LunchMenuIterator适配器转换接口为Iterator

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: