设计模式——迭代器模式

设计模式——迭代器模式
强烈推介IDEA2021.1.3破解激活,IntelliJ IDEA 注册码,2021.1.3IDEA 激活码 

在程序设计中,经常需要访问一个聚合对象中的各个元素,例如:我们使用 list 存储元素,通常的做法是将 list 的创建和遍历放在同一个类中。但这种方法不利于扩展,如果将存储方式更改为数组时,就需要更换迭代方式。违背了 “开闭原则”。“迭代器模式” 能较好的克服以上缺点,它在客户访问类与聚合类之间插入一个迭代器,这分离了聚合对象与遍历行为,对客户也隐藏了其内部细节,满足 “单一职责原则” 和 “开闭原则”,如 Java 中的 Collection、List、Set、Map 等都包含迭代器。

一、迭代模式基本介绍


1)、迭代器模式(Iterator Pattern):是常用的设计模式,属于行为型模式。
2)、如果集合元素是通过不同的方式实现的,有数组、list 等等,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
3)、迭代器模式,提供了一种遍历集合元素的统一接口,用一致的方法遍历结合元素,不需要知道集合对象的底层表示,即:不暴露其内部的结构。
4)、缺点:每个聚合对象都要一个迭代器,增加了类的个数,在一定程度上增加了系统的复杂度且不好管理。
5)、提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做 “单一责任原则”)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到迭代器。

二、迭代器模式结构类图


迭代器模式是通过将聚合对象的遍历行为分离出来,抽象成迭代器类来实现的,其目的是在不暴露聚合对象的内部结构的情况下,让外部代码透明地访问聚合的内部数据。

迭代器模式主要包含以下角色:
【1】抽象聚合(Aggregate)角色:定义了存储、添加、删除聚合对象以及创建迭代对象的接口。
【2】具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
【3】抽象迭代器(Iterator)角色:定义访问和遍历和聚合元素接口,通常包含 hasNext()、next()等方法。
【4】具体迭代器(ConcreteIterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。

设计模式——迭代器模式

三、迭代器模式案例分析


【1】抽象迭代器:使用 JDK 自带的 Iterator 接口,我们将源码粘贴过来,无需自行实现。子类需要实现 hasNext 和 next 方法

public interface Iterator<E> { boolean hasNext(); //使用泛型 E E next(); default void remove() { throw new UnsupportedOperationException("remove"); } default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); }
}

【2】具体迭代器:定义将 List 集合包装为 Iterator 遍历的对象 ListIterator

public class ListIterator implements Iterator<Object>{ //定义一个 List 集合 List<Phone> list; //构造器 public ListIterator(List<Phone> list) { this.list = list; } //获取位数 int index = 0; @Override public boolean hasNext() { if(list != null && list.size()>index) { return true; }else { return false; } } @Override public Object next() { Phone object = list.get(index); index+=1; return object; }
}

【3】具体迭代器:定义将 数组集合包装为 Iterator 遍历的对象 ArrayIterator

public class ArrayIterator implements Iterator<Object>{ //定义 电话数组 Phone[] phones; //下标 private int index = 0; //构造器 public ArrayIterator(Phone[] phones) { this.phones = phones; } @Override public boolean hasNext() { if(phones[index] != null && phones.length > index) { return true; }else { return false; } } @Override public Object next() { Phone phone = phones[index]; index+=1; return phone; }
}

【4】 定义 List 与 数组中存储的对象 Phone。

public class Phone { public String name; public String money; /** * @param name * @param money */ public Phone(String name, String money) { super(); this.name = name; this.money = money; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getMoney() { return money; } public void setMoney(String money) { this.money = money; }
}

【5】抽象聚合角色:手机的抽象接口 IPhone

public interface IPhone { //获取手机名称 public String getName(); //创建一个获取 Iterator 实例的方法 public Iterator<Object> createIterator(); //增加手机的方法 public void add(String name,String type);
}

【6】具体聚合角色:小米手机集合类,通过 List 进行封装,并创建一个返回 Iterator 的方法,使用迭代的方式遍历。

public class XiaoMiPhoneImpl implements IPhone{ //小米使用 list 存储产品 private List<Phone> xiaoMis = new ArrayList<Phone>(); //构造器 public XiaoMiPhoneImpl() { add("红米", "1200"); add("小米6", "2300"); add("小米7", "3200"); } @Override public String getName() { return "====小米手机===="; } //创建遍历器 @Override public Iterator<Object> createIterator() { return new ListIterator(xiaoMis); } //集合中添加小米产品 @Override public void add(String name, String money) { xiaoMis.add(new Phone(name, money)); }
}

【7】具体聚合角色:华为手机集合类,通过 数组 进行封装,并创建一个返回 Iterator 的方法,使用迭代的方式遍历。

public class HuaWeiPhoneImpl implements IPhone{ //存储华为手机的数据 Phone phone[]; private int index = 0; //构造器 public HuaWeiPhoneImpl() { phone = new Phone[5]; add("荣耀", "1300"); add("华为P8", "2000"); add("华为P20", "8000"); } @Override public String getName() { return "====华为手机===="; } @Override public Iterator<Object> createIterator() { return new ArrayIterator(phone); } @Override public void add(String name, String money) { phone[index] = new Phone(name,money); index +=1; }
}

【8】构造一个数据的工厂类:将所有的品牌集合在一块,通过 Iterator 接口的方式进行遍历输出。

public class OutputImpl { //定义一个集合 private List<IPhone> phones; //构造器 public OutputImpl(List<IPhone> phones) { this.phones = phones; } //输入方法 public void outPrit() { //先调用 list 自身带的迭代器 Iterator Iterator<IPhone> iterator = phones.iterator(); // 调用hasNext 方法 while(iterator.hasNext()) { IPhone iPhones = iterator.next(); //手机品牌名称 System.out.println(iPhones.getName()); //遍历品牌的所有手机,使用我们自己实现的Iterator pritlnPhone(iPhones.createIterator()); } } private void pritlnPhone(Iterator<Object> createIterator) { while(createIterator.hasNext()) { Phone phone = (Phone) createIterator.next(); System.out.println("品牌="+phone.getName()+"-----金额="+phone.getMoney()); } }
}

【9】客户端调用:创建手机品牌实体类,并将其组合在 List 中,调用输出工厂集合类即可。

public class Client { public static void main(String[] args) { //手机店集合 List<IPhone> phones = new ArrayList<IPhone>(); //创建华为手机 == 数组 HuaWeiPhoneImpl huaWeis = new HuaWeiPhoneImpl(); //创建小米手机 == list XiaoMiPhoneImpl xiaoMis = new XiaoMiPhoneImpl(); //将其都加入到手机店集合 phones.add(huaWeis); phones.add(xiaoMis); //调用公共的输入类 OutputImpl outputImpl = new OutputImpl(phones); outputImpl.outPrit(); /** * 结构如下: * ====华为手机==== 品牌=荣耀-----金额=1300 品牌=华为P8-----金额=2000 品牌=华为P20-----金额=8000 ====小米手机==== 品牌=红米-----金额=1200 品牌=小米6-----金额=2300 品牌=小米7-----金额=3200 */ }
}

四、迭代器模式应用源码分析


分析一下 arrayList 的 iterator 的使用

【1】先了解下 ArrayList 的 Iterator 的使用:

public class IteratorDemo { public static void main(String[] args) { List<String> a = new ArrayList<>(); a.add("t");// .. // 获取到迭代器 Iterator<String> Itr = a.iterator(); while (Itr.hasNext()) { System.out.println(Itr.next()); } }
}

【2】进入 ArrayList 的源码:实现了 List 接口,实现了 Iterator 方法,返回遍历对象:Iterator。相当于具体聚合对象。

public class ArrayList<E> extends AbstractList<E> implements List<E>
{ ... public Iterator<E> iterator() { return new Itr(); } ...
}

【3】进入 List 接口查看:发现包含一个 Iterator 的抽象方法 。相当于抽象聚合对象

public interface List<E> extends Collection<E> { ... Iterator<E> iterator(); ...
}

【4】我们进入返回的 Iterator 对象的类 Itr ,是 ArraList 类的内部类。查看 hasNext()方法,会发现遍历的对象是 Object[] 数组,具体的迭代器类(实现 hasNext 和 Next 方法)

private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; public boolean hasNext() { return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } ...... }

【5】上述具体迭代器角色实现了 Iterator 接口,也就是抽象迭代器角色。与我们的案例中实现同一个接口,就不展示了。
【6】源码类图展示:同时多添加了两个具体的实现类:KeyIterator 与 LinkedList
设计模式——迭代器模式

本文来源程序猿进阶,由架构君转载发布,观点不代表Java架构师必看的立场,转载请标明来源出处:https://javajgs.com/archives/8274

发表评论