zoukankan      html  css  js  c++  java
  • 迭代器模式

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

      相信java程序员对迭代器模式都不陌生,我们集合类就是采用的这种模式,但是为什么要用呢?下面我先自己写一版demo版的Arraylist、linkedList和hashmap。

    package iterator;
    
    public class MyArrayList<E> {
    
        private final int INCREMENT = 10;
        @SuppressWarnings("unchecked")
        private Object[] array = new Object[10];
        private int size;
        @SuppressWarnings("unchecked")
        public void add(E e) {
            if(size<array.length) {
                array[size++] = e;
            }else {
                E[] copy = (E[]) new Object[array.length+ INCREMENT];
                System.arraycopy(array, 0, copy, 0, size);
                copy[size++] = e;
                array= copy;
            }
        }
        @SuppressWarnings("unchecked")
        public Object[] toArray() {
            Object[] copy =  new Object[size];
            System.arraycopy(array, 0, copy, 0, size);
            return copy;
        }
        @SuppressWarnings("unchecked")
        public E get(int index) {
            return (E) array[index];
        }
    }
    package iterator;
    
    public class MyLinkedList<E> {
    
        private Entry<E> header = new Entry<E>(null, null, null);
        private Entry<E> last ;
        private int size;
        public MyLinkedList() {
            header.next =header.previous=last=header;
        }
    
        public void add(E e) {
            Entry<E> entry = new Entry<E>(e, last, null);
            entry.previous.next = entry;
            last = entry;
            size++;
        }
        private static class Entry<E>{
            E value;
            Entry<E> previous;
            Entry<E> next;
            public Entry(E value,Entry<E> previous, Entry<E> next) {
                super();
                this.value = value;
                this.previous = previous;
                this.next = next;
            }
        }
        
         public Object[] toArray(){
                Object[] result = new Object[size];
                int i = 0;
                for (Entry<E> e = header.next; e != null; e = e.next)
                    result[i++] = e.value;
                return result;
            }
    }
    package iterator;
    
    public class MyHashMap {
    
        private int size;
        
        private MyEntry[] table;
        
        public MyHashMap() {
            super();
            this.size = 0;
            this.table = new MyEntry[10];
        }
        
        private int index(Object key) {
            return key.hashCode()% table.length;
        }
        public int size() {
            return this.size;
        }
        
        public void put (Object key,Object value) {
            if(key ==null) return;
            int index = index(key);
            MyEntry entry = table[index];
            while(entry != null) {
                if(entry.getKey().hashCode()== key.hashCode() &&(entry.getKey()== key || entry.getKey().equals(key))) {
                    entry.setValue(value);
                    return;
                }
                entry = entry.getNext();
            }
            add(index, key, value);
            size ++;
            
        }
        
        private void add(int index,Object key,Object value) {
            MyEntry newEntry = new MyEntry(key, value, table[index]);
            table[index] = newEntry;
        }
        
        public Object get(Object key) {
            if(key==null) return null;
            MyEntry entry = getEntry(key);
            return entry==null?null:entry.getValue();
        }
        
        public MyEntry getEntry(Object key) {
            int index = index(key);
            MyEntry entry = table[index];
            while(entry != null) {
                if(entry.getKey().hashCode()== key.hashCode() &&(entry.getKey()== key || entry.getKey().equals(key))) {
                    return entry;
                }
                entry =entry.getNext();
            }
            return null;
        }
        
        static class MyEntry{
            private final Object key;
            private Object value;
            private MyEntry next;
            public MyEntry(Object key, Object value, MyEntry next) {
                super();
                this.key = key;
                this.value = value;
                this.next = next;
            }
            public Object getValue() {
                return value;
            }
            public void setValue(Object value) {
                this.value = value;
            }
            public MyEntry getNext() {
                return next;
            }
            public void setNext(MyEntry next) {
                this.next = next;
            }
            public Object getKey() {
                return key;
            }
            
            
        }
        
        public Object[] toArray(){
            MyArrayList<MyEntry> result = new MyArrayList<MyEntry>();
            for (int i = 0; i < table.length; ++i) {
                for (MyEntry e = table[i]; e != null; e = e.next)
                    result.add(e);
            }
            return result.toArray();
        }
        
    }

      在代码中,我都是通过一个toArray方法将集合中的元素存放到数组中,然后使用时通过这个方法获取数组,然后按数组的方式去遍历,当然,为了迎合面向接口的思想,你可以添加一个接口规定toArray的行为,让三个类去实现它。但是在这里有一个很大的弊端,那就是在使用数组遍历集合类的时候,其实遍历了两次。 在这三个类中,由于System的arraycopy和set的toArray方法是黑箱子,所以最明显的便是LinkedList的实现,它是先遍历了一遍链表,做出来一个数组,然后当客户端获得到这个数组的时候,则需要再来一次循环,去遍历每一个元素。当然针对arraylist,我们可以通过数组自带的index来遍历,同时还解决了二次遍历的问题,但是其它两个就不能这样做。

      三个集合类,如果统一提供数组给客户端遍历,那么在遍历过程中会出现重复遍历的现象。而如果消除这种重复遍历,则由于内部数据结构的不同,三个集合类无法做到像提供数组一样,给客户端提供统一的遍历方式。为了解决上面的问题,迭代器模式就随之出现了。我们先来看看迭代器模式在百度百科中的类图。

      

      看着上面的类图,我们可以分析出来,上面我们所写的ArrayList等三个类都属于ConcreteAggregate的位置,如果给toarray抽象出接口,那么就相当于Aggregate,我们所少的就是Iterator接口和具体的迭代器。这里就不再自己写了,直接用JDK的。

      Iterator源码,所有的迭代器实现这个接口

    package java.util;
    
    import java.util.function.Consumer;
    
    public interface Iterator<E> {
    
        boolean hasNext();
    
        E next();
    
        default void remove() {
            throw new UnsupportedOperationException("remove");
        }
    
        default void forEachRemaining(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            while (hasNext())
                action.accept(next());
        }
    }

      Iterable源码,集合类实现这个接口,表名自己可迭代

    package java.lang;
    
    import java.util.Iterator;
    import java.util.Objects;
    import java.util.Spliterator;
    import java.util.Spliterators;
    import java.util.function.Consumer;
    
    public interface Iterable<T> {
     
        Iterator<T> iterator();
    
        default void forEach(Consumer<? super T> action) {
            Objects.requireNonNull(action);
            for (T t : this) {
                action.accept(t);
            }
        }
    
        default Spliterator<T> spliterator() {
            return Spliterators.spliteratorUnknownSize(iterator(), 0);
        }
    }

      改造后的集合类

    package iterator;
    
    import java.util.Iterator;
    
    public class MyArrayList<E> implements Iterable<E>{
    
        private final int INCREMENT = 10;
        private Object[] array = new Object[10];
        private int size;
        @SuppressWarnings("unchecked")
        public void add(E e) {
            if(size<array.length) {
                array[size++] = e;
            }else {
                E[] copy = (E[]) new Object[array.length+ INCREMENT];
                System.arraycopy(array, 0, copy, 0, size);
                copy[size++] = e;
                array= copy;
            }
        }
        public Object[] toArray() {
            Object[] copy =  new Object[size];
            System.arraycopy(array, 0, copy, 0, size);
            return copy;
        }
        @SuppressWarnings("unchecked")
        public E get(int index) {
            return (E) array[index];
        }
        @Override
        public Iterator<E> iterator() {
            
            return new ArrayIterator();
        }
        
        private class ArrayIterator implements Iterator<E>{
            int cursor;
            @Override
            public boolean hasNext() {
                return cursor<size;
            }
    
            @SuppressWarnings("unchecked")
            @Override
            public E next() {
                int i = cursor;
                 Object[] elementData = MyArrayList.this.array;
                 cursor = i + 1;
                 return (E) elementData[i];
            }
            
        }
    }
    package iterator;
    
    import java.util.Iterator;
    
    public class MyLinkedList<E> implements Iterable<E>{
    
        private Entry<E> header = new Entry<E>(null, null, null);
        private Entry<E> last ;
        private int size;
        public MyLinkedList() {
            header.next =header.previous=last=header;
        }
    
        public void add(E e) {
            Entry<E> entry = new Entry<E>(e, last, null);
            entry.previous.next = entry;
            last = entry;
            size++;
        }
        private static class Entry<E>{
            E value;
            Entry<E> previous;
            Entry<E> next;
            public Entry(E value,Entry<E> previous, Entry<E> next) {
                super();
                this.value = value;
                this.previous = previous;
                this.next = next;
            }
        }
        
         public Object[] toArray(){
                Object[] result = new Object[size];
                int i = 0;
                for (Entry<E> e = header.next; e != null; e = e.next)
                    result[i++] = e.value;
                return result;
            }
    
        @Override
        public Iterator<E> iterator() {
            return new LinkIterator();
        }
        
        private class LinkIterator implements Iterator<E>{
            private Entry<E> lastReturned;
            private Entry<E> next;
            private int nextIndex;
            LinkIterator(){
                next = header.next;
            }
            @Override
            public boolean hasNext() {
                return nextIndex < size;
            }
    
            @Override
            public E next() {
                lastReturned = next;
                nextIndex++;
                next= next.next;
                return lastReturned.value;
            }
            
        }
    }
    package iterator;
    
    import java.util.Iterator;
    import java.util.NoSuchElementException;
    
    public class MyHashMap<E> implements Iterable<E>{
    
        private int size;
        
        private MyEntry[] table;
        
        public MyHashMap() {
            super();
            this.size = 0;
            this.table = new MyEntry[10];
        }
        
        private int index(Object key) {
            return key.hashCode()% table.length;
        }
        public int size() {
            return this.size;
        }
        
        public void put (Object key,Object value) {
            if(key ==null) return;
            int index = index(key);
            MyEntry entry = table[index];
            while(entry != null) {
                if(entry.getKey().hashCode()== key.hashCode() &&(entry.getKey()== key || entry.getKey().equals(key))) {
                    entry.setValue(value);
                    return;
                }
                entry = entry.getNext();
            }
            add(index, key, value);
            size ++;
            
        }
        
        private void add(int index,Object key,Object value) {
            MyEntry newEntry = new MyEntry(key, value, table[index]);
            table[index] = newEntry;
        }
        
        public Object get(Object key) {
            if(key==null) return null;
            MyEntry entry = getEntry(key);
            return entry==null?null:entry.getValue();
        }
        
        public MyEntry getEntry(Object key) {
            int index = index(key);
            MyEntry entry = table[index];
            while(entry != null) {
                if(entry.getKey().hashCode()== key.hashCode() &&(entry.getKey()== key || entry.getKey().equals(key))) {
                    return entry;
                }
                entry =entry.getNext();
            }
            return null;
        }
        
        public static class MyEntry{
            private final Object key;
            private Object value;
            private MyEntry next;
            public MyEntry(Object key, Object value, MyEntry next) {
                super();
                this.key = key;
                this.value = value;
                this.next = next;
            }
            public Object getValue() {
                return value;
            }
            public void setValue(Object value) {
                this.value = value;
            }
            public MyEntry getNext() {
                return next;
            }
            public void setNext(MyEntry next) {
                this.next = next;
            }
            public Object getKey() {
                return key;
            }
            
            
        }
        
        public Object[] toArray(){
            MyArrayList<MyEntry> result = new MyArrayList<MyEntry>();
            for (int i = 0; i < table.length; ++i) {
                for (MyEntry e = table[i]; e != null; e = e.next)
                    result.add(e);
            }
            return result.toArray();
        }
    
        @Override
        public Iterator<E> iterator() {
            return new HashIterator();
        }
         private  class HashIterator implements Iterator<E>{
                MyEntry next;        // next entry to return
                @SuppressWarnings("unused")
                MyEntry current;     // current entry
                int index;             // current slot
    
                HashIterator() {
                    MyEntry[] t = table;
                    current = next = null;
                    index = 0;
                    if (t != null && size > 0) { // advance to first entry
                        do {} while (index < t.length && (next = t[index++]) == null);
                    }
                }
    
                public final boolean hasNext() {
                    return next != null;
                }
                @SuppressWarnings("unchecked")
                @Override
                public E next() {
                    MyEntry[] t;
                    MyEntry e = next;
                    if (e == null)
                        throw new NoSuchElementException();
                    if ((next = (current = e).next) == null && (t = table) != null) {
                        do {} while (index < t.length && (next = t[index++]) == null);
                    }
                    return (E) e;
                }
            }
    }

      改造后的集合类遍历方式

    package iterator;
    
    import java.util.Iterator;
    
    public class Client {
    
        public static void main(String[] args) {
            
            MyArrayList<String> mar = new MyArrayList<String>();
            mar.add("a");
            mar.add("b");
            mar.add("c");
            mar.add("d");
            Iterator<String> it = mar.iterator();
            while(it.hasNext()) {
            String e = it.next();
            System.out.println(e);
        }
    //        MyLinkedList<String> myl = new MyLinkedList<>();
    //        myl.add("a");
    //        myl.add("b");
    //        myl.add("c");
    //        myl.add("d");
    //        Iterator<String> it = myl.iterator();
    //        while(it.hasNext()) {
    //            String e = it.next();
    //            System.out.println(e);
    //        }
    //        MyHashMap<MyEntry> map = new MyHashMap<MyEntry>();
    //        map.put("asd", "asd");
    //        map.put("zxc", "zx");
    //        map.put("qwe", "qwe");
    //        map.put("bnm", "bnm");
    //        Iterator<MyEntry> it = map.iterator();
    //        while(it.hasNext()) {
    //            MyEntry e = it.next();
    //            System.out.println(e.getKey() +"-----"+e.getValue());
    //        }
            
        }
    }

      通过以上例子,可以看到迭代器模式解决了哪些问题:

      1、迭代器模式可以提供统一的迭代方式,这个要归功于Iterator接口。

      2、迭代器模式可以在对客户透明的前提下,做出各种不同的迭代方式。

      3、在迭代的时候不需要暴露聚合对象的内部表示,我们只需要认识Iterator即可。

      4、解决了基于数组的迭代方式中重复遍历的问题。

      当然JDK中Hashmap并没有实现Iterable接口,并且官方也不推荐使用迭代器去遍历,但是底层的原理是一致的,有兴趣的同学可以自己去看下源码。

      

  • 相关阅读:
    线程池参数设置技巧
    线程池的七个参数
    bug篇——Windows启动redis报错Creating Server TCP listening socket 127.0.0.1:6379: bind: No error
    总结篇——git本地仓库上传更新到github
    实例篇——springboot自定义拦截器
    总结篇——从零搭建maven多模块springboot+mybatis项目
    bug篇——MySQL的时区问题
    工具类篇——时间处理Calendar类
    安装篇——nginx安装ssl模块转发https请求
    总结篇——nginx代理服务器
  • 原文地址:https://www.cnblogs.com/hhhshct/p/10260556.html
Copyright © 2011-2022 走看看