疊代器模式
- 細說疊代器模式
-
- 細說疊代器模式
-
- 定義
- UML模型
- 場景
-
- 場景一
- 場景二
- 代碼
-
- 代碼一
- 代碼二
- 基于UML的代碼
- 疊代器模式應用和注意事項
細說疊代器模式
提示:
部落客:章飛 _906285288的部落格
部落格位址:http://blog.csdn.net/qq_29924041
細說疊代器模式
記得剛開始在學習se的中的集合的時候,有個繞不開的坎,就是疊代器,幾乎所有的集合類都是Iterator接口的子類,在周遊的時候不需要關系其周遊的規則和順序情況,那些是針對已有集合進行的疊代,但是如果在實際應用過程中,需要對某一類對象集進行操作的時候,能不能應用這種設計模式呢??下面來簡單講解下
定義
疊代器模式(Iterator),提供一種方法順序通路一個聚合對象中的各種元素,而又不暴露該對象的内部表示。其實主要的意思就是疊代器模式它提供了一種方法,可以通路一個容器對象中的各個元素。目前來看,這種疊代器模式,使用場景并不是特别多。
疊代器對象是為了容器進行服務的,什麼是容器??Collection集合類型,Set類型都是容器的一種。而疊代器主要也就是為了周遊它們而誕生的。
UML模型
從疊代器對象中可以看到有以下幾種角色
1:Iterator 疊代器對象,負責定義通路和周遊使用的
2:ConcreteIterator 具體的疊代器對象,負責實作疊代器,實作周遊使用的
3:Aggregate抽象的容器,建立具體的疊代器使用的
4:Concrete Aggregate具體的容器,實作容器接口,建立出容納疊代器的對象
場景
場景一
本案例來自設計模式之禅,就是怎麼去周遊一個項目,通常是有兩種寫法, 一種是直接在使用的時候沒有封裝思想,直接将項目放入集合中進行周遊,這種方法最簡單和顯而易見。另外一種方法其實就是疊代器模式,本身其實就将對象封裝成了一個容器,通過疊代器來對容器内部的資訊進行通路。
場景二
在java的集合類的體系中,疊代器的使用時無處不在的,從源碼的角度簡單分析下疊代器,其實在源碼中主要包括了Collection接口,Iterable接口,Iterator接口,剩下的其實都是一些具體的實作類對象。
代碼
代碼一
package src.com.zzf.designpattern.iteratorpattern.demo2;
/**
* 頂層的疊代器實作類
* @author zhouzhangfei`在這裡插入代碼片`
*
*/
public interface Iterator {
public boolean hasNext();
public Object next();
public void remove();
}
package src.com.zzf.designpattern.iteratorpattern.demo2;
/**
* 此類主要是疊代器的接口擴充卡類,為了避免需要特殊的方法會污染頂層的疊代器接口
* @author zhouzhangfei
*
*/
public interface IProjectIterator extends Iterator {
}
package src.com.zzf.designpattern.iteratorpattern.demo2;
/**
* 抽象的容器,在這裡主要是針對項目本身來說的,也就是說這是一個抽象的項目容器
* @author zhouzhangfei
*
*/
public interface IProject {
public String getProjectInfo();
public void add(String name,int num,int cost);
public IProjectIterator iterator();
}
package src.com.zzf.designpattern.iteratorpattern.demo2;
import java.util.ArrayList;
public class Project2 implements IProject{
//定義一個項目清單,說有的項目都放在這裡
private ArrayList<IProject> projectList = new ArrayList<IProject>();
//項目名稱
private String name = "";
//項目成員數量
private int num = 0;
//項目費用
private int cost = 0;
private Project2(String name,int num,int cost) {
this.name = name;
this.num = num;
this.cost = cost;
}
public Project2() {
// TODO Auto-generated constructor stub
}
public String getProjectInfo() {
String info = "";
//獲得項目的名稱
info = info+ "項目名稱是:" + this.name;
//獲得項目人數
info = info + "\t項目人數: "+ this.num;
//項目費用
info = info+ "\t 項目費用:"+ this.cost;
return info;
}
public void add(String name, int num, int cost) {
// TODO Auto-generated method stub
this.projectList.add(new Project2(name,num,cost));
}
public IProjectIterator iterator() {
// TODO Auto-generated method stub
return new ProjectIterator(projectList);
}
}
package src.com.zzf.designpattern.iteratorpattern.demo2;
import java.util.ArrayList;
/**
* 項目容器的實作類
* @author zhouzhangfei
*
*/
public class ProjectIterator implements IProjectIterator{
//所有的項目都放在這裡ArrayList中
private ArrayList<IProject> projectList = new ArrayList<IProject>();
private int currentItem = 0;
//構造函數傳入projectList
public ProjectIterator(ArrayList<IProject> projectList){
this.projectList = projectList;
}
public boolean hasNext() {
// TODO Auto-generated method stub
boolean b = true;
if (this.currentItem >= projectList.size() || this.projectList.get(currentItem) == null) {
b = false;
}
return b;
}
public Object next() {
// TODO Auto-generated method stub
return (IProject)this.projectList.get(this.currentItem++);
}
public void remove() {
// TODO Auto-generated method stub
}
}
package src.com.zzf.designpattern.iteratorpattern.demo2;
public class Boss {
public static void main(String[] args) {
IProject project = new Project2();
//增加星球大戰項目
project.add("星球大戰項目ddddd",10,100000);
//增加扭轉時空項目
project.add("扭轉時空項目",100,10000000);
//增加超人改造項目
project.add("超人改造項目",10000,1000000000);
//這邊100個項目
for(int i=4;i<104;i++){
project.add("第"+i+"個項目",i*5,i*1000000);
}
IProjectIterator projectIterator = project.iterator();
while(projectIterator.hasNext()){
IProject p = (IProject)projectIterator.next();
System.out.println(p.getProjectInfo());
}
}
}
代碼二
以下代碼主要是從源碼角度檢視下系統的實作
Iterable接口,中
public interface Iterable<T> {
//建立一個疊代器
Iterator<T> iterator();
/**
* Performs the given action for each element of the {@code Iterable}
* until all elements have been processed or the action throws an
* exception. Unless otherwise specified by the implementing class,
* actions are performed in the order of iteration (if an iteration order
* is specified). Exceptions thrown by the action are relayed to the
* caller.
*
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* for (T t : this)
* action.accept(t);
* }</pre>
*
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
* @since 1.8
*/
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
/**
* Creates a {@link Spliterator} over the elements described by this
* {@code Iterable}.
*
* @implSpec
* The default implementation creates an
* <em><a href="Spliterator.html#binding" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >early-binding</a></em>
* spliterator from the iterable's {@code Iterator}. The spliterator
* inherits the <em>fail-fast</em> properties of the iterable's iterator.
*
* @implNote
* The default implementation should usually be overridden. The
* spliterator returned by the default implementation has poor splitting
* capabilities, is unsized, and does not report any spliterator
* characteristics. Implementing classes can nearly always provide a
* better implementation.
*
* @return a {@code Spliterator} over the elements described by this
* {@code Iterable}.
* @since 1.8
*/
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
具體的疊代器的接口,可以看到,它提供的方法hasNext,next,remove等
/*
public interface Iterator<E> {
/**
* Returns {@code true} if the iteration has more elements.
* (In other words, returns {@code true} if {@link #next} would
* return an element rather than throwing an exception.)
*
* @return {@code true} if the iteration has more elements
*/
boolean hasNext();
/**
* Returns the next element in the iteration.
*
* @return the next element in the iteration
* @throws NoSuchElementException if the iteration has no more elements
*/
E next();
/**
* Removes from the underlying collection the last element returned
* by this iterator (optional operation). This method can be called
* only once per call to {@link #next}. The behavior of an iterator
* is unspecified if the underlying collection is modified while the
* iteration is in progress in any way other than by calling this
* method.
*
* @implSpec
* The default implementation throws an instance of
* {@link UnsupportedOperationException} and performs no other action.
*
* @throws UnsupportedOperationException if the {@code remove}
* operation is not supported by this iterator
*
* @throws IllegalStateException if the {@code next} method has not
* yet been called, or the {@code remove} method has already
* been called after the last call to the {@code next}
* method
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
/**
* Performs the given action for each remaining element until all elements
* have been processed or the action throws an exception. Actions are
* performed in the order of iteration, if that order is specified.
* Exceptions thrown by the action are relayed to the caller.
*
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* while (hasNext())
* action.accept(next());
* }</pre>
*
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
* @since 1.8
*/
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
結合類接口Collection,可以看到Collections繼承自Iteratable接口允許建立一個Iterator接口對象,并且補充了很多接口對象的方法。而Collection的子類有Set,List,Map.SortedSet等等。說明其子類也都具有相同的特性
package java.util;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* @author Josh Bloch
* @author Neal Gafter
* @see Set
* @see List
* @see Map
* @see SortedSet
* @see SortedMap
* @see HashSet
* @see TreeSet
* @see ArrayList
* @see LinkedList
* @see Vector
* @see Collections
* @see Arrays
* @see AbstractCollection
* @since 1.2
*/
public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
// Modification Operations
boolean add(E e);
boolean remove(Object o);
// Bulk Operations
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
boolean retainAll(Collection<?> c);
void clear();
boolean equals(Object o);
int hashCode();
/**
* Creates a {@link Spliterator} over the elements in this collection.
*
* Implementations should document characteristic values reported by the
* spliterator. Such characteristic values are not required to be reported
* if the spliterator reports {@link Spliterator#SIZED} and this collection
* contains no elements.
*
* <p>The default implementation should be overridden by subclasses that
* can return a more efficient spliterator. In order to
* preserve expected laziness behavior for the {@link #stream()} and
* {@link #parallelStream()}} methods, spliterators should either have the
* characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be
* <em><a href="Spliterator.html#binding" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >late-binding</a></em>.
* If none of these is practical, the overriding class should describe the
* spliterator's documented policy of binding and structural interference,
* and should override the {@link #stream()} and {@link #parallelStream()}
* methods to create streams using a {@code Supplier} of the spliterator,
* as in:
* <pre>{@code
* Stream<E> s = StreamSupport.stream(() -> spliterator(), spliteratorCharacteristics)
* }</pre>
* <p>These requirements ensure that streams produced by the
* {@link #stream()} and {@link #parallelStream()} methods will reflect the
* contents of the collection as of initiation of the terminal stream
* operation.
*
* @implSpec
* The default implementation creates a
* <em><a href="Spliterator.html#binding" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >late-binding</a></em> spliterator
* from the collections's {@code Iterator}. The spliterator inherits the
* <em>fail-fast</em> properties of the collection's iterator.
* <p>
* The created {@code Spliterator} reports {@link Spliterator#SIZED}.
*
* @implNote
* The created {@code Spliterator} additionally reports
* {@link Spliterator#SUBSIZED}.
*
* <p>If a spliterator covers no elements then the reporting of additional
* characteristic values, beyond that of {@code SIZED} and {@code SUBSIZED},
* does not aid clients to control, specialize or simplify computation.
* However, this does enable shared use of an immutable and empty
* spliterator instance (see {@link Spliterators#emptySpliterator()}) for
* empty collections, and enables clients to determine if such a spliterator
* covers no elements.
*
* @return a {@code Spliterator} over the elements in this collection
* @since 1.8
*/
@Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
}
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
}
最後在附上一張集合的關系圖
圖檔摘自https://blog.csdn.net/lyabc123456/article/details/80390619
很容易可以看出疊代器的重要性。
基于UML的代碼
package src.com.zzf.designpattern.iteratorpattern.demo3;
/**
* 抽象的疊代器接口
* @author zhouzhangfei
*
*/
public interface Iterator {
//下一個元素
public Object next();
//判斷是否含有下一個
public boolean hasNext();
//移除目前的元素
public boolean remove();
}
package src.com.zzf.designpattern.iteratorpattern.demo3;
import java.util.Vector;
/**
* 具體的疊代器的實作類
* @author zhouzhangfei
*
*/
public class ConcreteIterator implements Iterator {
private Vector<Object> mVector = new Vector<>();
private int cursor = 0;
public ConcreteIterator(Vector vector){
this.mVector = vector;
}
@Override
public Object next() {
// TODO Auto-generated method stub
Object result = null;
if(this.hasNext()){
result = this.mVector.get(this.cursor++);
}else{
result = null;
}
return result;
}
@Override
public boolean hasNext() {
// TODO Auto-generated method stub
if(this.cursor == this.mVector.size()){
return false;
}else{
return true;
}
}
@Override
public boolean remove() {
// TODO Auto-generated method stub
this.mVector.remove(this.cursor);
return false;
}
}
package src.com.zzf.designpattern.iteratorpattern.demo3;
/**
* 抽象的容器接口
* @author zhouzhangfei
*
*/
public interface Aggregate {
/**
* 增加元素
* @param object
*/
public void add(Object object);
/**
* 減少元素
* @param object
*/
public void remove(Object object);
/**
* 建立疊代器對象
* @return
*/
public Iterator iterator();
}
package src.com.zzf.designpattern.iteratorpattern.demo3;
import java.util.Vector;
/**
* 具體的容器接口
* @author zhouzhangfei
*
*/
public class ConcreteAggregate implements Aggregate{
private Vector mVector = new Vector<>();
@Override
public void add(Object object) {
// TODO Auto-generated method stub
mVector.add(object);
}
@Override
public void remove(Object object) {
// TODO Auto-generated method stub
mVector.remove(object);
}
@Override
public Iterator iterator() {
// TODO Auto-generated method stub
return new ConcreteIterator(mVector);
}
}
package src.com.zzf.designpattern.iteratorpattern.demo3;
/**
* 測試類
* @author zhouzhangfei
*
*/
public class Client {
public static void main(String[] args) {
Aggregate mAggregate = new ConcreteAggregate();
mAggregate.add("123");
mAggregate.add("abc");
mAggregate.add("abcd");
mAggregate.add("abcde");
mAggregate.add("abcdef");
mAggregate.add("abcdefg");
Iterator iterator = mAggregate.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
疊代器模式應用和注意事項
疊代器模式使用時要明确你是要單獨操作你的對象還是去操作對象的容器。
其實在實際開發中自己去寫一個疊代器模式的場景不多。而且java的jdk中其實已經為我們準備好了疊代器,如果自己再去創造的話,顯得有點多餘了,不過這個設計模式依舊相當的重要
歡迎繼續通路,我的部落格