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

    迭代器是行为型设计模式的一种,是一种非常简单的设计模式。

    转载请注明出处 http://www.cnblogs.com/zrtqsk/p/3716173.html,谢谢!

    一、介绍

      先来看一下《研磨设计模式》的定义——提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。

      迭代器模式的本质是——控制访问聚合对象中的元素

      Java中有的聚合对象主要是Collection类、Map类的各子类对象。同样的,数组也算一种聚合对象。迭代器模式就是希望从外部用同一种方式去访问不同的聚合对象。这个怎么做呢?

      说白了,就是创建一个迭代类,持有聚合对象,并且提供迭代这个聚合对象的方法。这个迭代类怎么得到呢?让原本的聚合对象增加一个方法,可以用来返回一个迭代对象,返回时,将自身传递给这个迭代对象。我们得到了这个迭代对象,就可以轻松的在外部访问这个聚合对象了。

    二、我的实现

    1、假设我们本身有一个包含简单功能的聚合类MyList,如下:

     1 public class MyList<T> {
     2 
     3     private Object[] elements;
     4     //容量
     5     private int capacity = 10;
     6     //当前大小
     7     private int size = 0;
     8     
     9     //指定容量的构造方法
    10     public MyList(int capacity){
    11         this.capacity = capacity;
    12         elements = new Object[10];
    13     }
    14     
    15     //默认构造方法
    16     public MyList(){
    17         this(10);
    18     }
    19     
    20     public int size(){
    21         return size;
    22     }
    23     
    24     public T get(int i){
    25         if(i > capacity){
    26             System.out.println("List数组越界");
    27             return null;
    28         }else {
    29             return (T) elements[i];
    30         }
    31     }
    32     
    33     public void add(T obj){
    34         if(size >= capacity){
    35             //扩容
    36         }else {
    37             elements[size ++] = obj;
    38         }
    39     }
    40 }

    2、测试一下:

     1 public class Test {
     2 
     3     public static void main(String[] args)
     4     {
     5         MyList<Apple> list = new MyList<Apple>();
     6         list.add(new Apple("a"));
     7         list.add(new Apple("b"));
     8         System.out.println(list.get(0));
     9         System.out.println(list.get(1));
    10         System.out.println(list.get(3));
    11     }
    12 }
    13 
    14 class Apple{
    15     private String name;
    16     
    17     public Apple(String name){
    18         this.name = name;
    19     }
    20     
    21     public String toString(){
    22         return "Apple:" + name;
    23     }
    24     
    25 }

    3、结果如下:

    Apple:a
    Apple:b
    List数组越界
    null

    可见功能正常。

    4、我们需要从外部访问这个聚合对象,该怎么做呢?

    如前面说的,写一个简单的访问数据的接口,包含简单的迭代聚合对象的功能如下:

    1 public interface Iterator<T> {
    2     
    3     public T next();
    4     
    5     public boolean hasNext();
    6 }

    5、简单的实现类;

     1 public class IteratorImpl<T> implements Iterator<T> {
     2 
     3     private int index = 0;
     4     MyList list = null;
     5     public IteratorImpl(MyList list){
     6         this.list = list;
     7     }
     8 
     9     @Override
    10     public T next()
    11     {
    12         return (T) list.get(index++);
    13     }
    14 
    15     @Override
    16     public boolean hasNext()
    17     {
    18         boolean flag = false;
    19         if(list.get(index) != null){
    20             flag = true;
    21         }
    22         return flag;
    23     } 
    24 }

    6、构建一个简单的抽象类AbstractList,而实际上List的大部分方法都可以放到这个抽象类来,这里为了演示方便,如下:

    1 public abstract class AbstractList {
    2 
    3     public abstract Iterator iterator();
    4 }

    7、刚才的MyList继承这个抽象类,其实现方法如下:

    1 @Override
    2     public Iterator iterator()
    3     {
    4         return new IteratorImpl(this);
    5     }

    非常简单!

    8、下面我们就是测试,测试类比之前改变一点点,如下;

     1 public class Test {
     2 
     3     public static void main(String[] args)
     4     {
     5         MyList<Apple> list = new MyList<Apple>();
     6         list.add(new Apple("a"));
     7         list.add(new Apple("b"));
     8 //        System.out.println(list.get(0));
     9 //        System.out.println(list.get(1));
    10 //        System.out.println(list.get(3));
    11         Iterator it = list.iterator();
    12         while(it.hasNext()){
    13             System.out.println(it.next());
    14         }
    15     }
    16 }

    9,结果如下:

    Apple:a
    Apple:b

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

    三、Java的迭代器

      通常而言,我们遍历一个聚合对象除了使用Iterator外,还有一种更简便的方法,那就是用简易的for循环——for(Type t : Collection)。但是当我们用这个方式去访问上文我自定义的聚合对象MyList的时候,发现编译错误。错误提示说,因为我们没有实现java.lang.Iterable接口。  这个接口位于java.lang包下,意味着我们不用额外导包了。我们来看一下这个接口的源代码:

    package java.lang;
    
    import java.util.Iterator;
    
    public interface Iterable<T> {
    
        Iterator<T> iterator();
    }

    可见,这个接口只有一个方法,用来返回一个java.util.Iterator接口对象。相当于我们刚才的抽象类。

      Java的迭代器实现主要就是围绕着这两个接口,我们来看一下java.util.Iterator的源代码

    package java.util;
    
    public interface Iterator<E> {
    
        boolean hasNext();
    
        E next();
    
        void remove();
    }

    可以看到,这个接口是非常简单的。跟上面我自定义的Iterator相比,只是多了一个void remove()方法。

      下面我们将上面的例子改为Java的迭代器实现。通常而言,由于一个Iterator的实现类是对应一个聚合对象的。为了提高内聚性,我们应该将Iterator实现类作为聚合对象的内部类。而JDK也是这么做的。如下:

     1 import java.util.Iterator;
     2 
     3 //实现Iterable接口
     4 public class MyList<T> implements Iterable<T>{
     5 
     6     private Object[] elements;
     7     // 容量
     8     private int capacity = 10;
     9     // 当前大小
    10     private int size = 0;
    11 
    12     // 指定容量的构造方法
    13     public MyList(int capacity)
    14     {
    15         this.capacity = capacity;
    16         elements = new Object[10];
    17     }
    18 
    19     // 默认构造方法
    20     public MyList()
    21     {
    22         this(10);
    23     }
    24 
    25     public int size()
    26     {
    27         return size;
    28     }
    29 
    30     public T get(int i)
    31     {
    32         if (i > capacity)
    33         {
    34             System.out.println("List数组越界");
    35             return null;
    36         }
    37         else
    38         {
    39             return (T) elements[i];
    40         }
    41     }
    42 
    43     public void add(T obj)
    44     {
    45         if (size >= capacity)
    46         {
    47             // 扩容
    48         }
    49         else
    50         {
    51             elements[size++] = obj;
    52         }
    53     }
    54 
    55     //返回java.util.Iterator对象
    56     @Override
    57     public Iterator iterator()
    58     {
    59         return new IteratorImpl(this);
    60     }
    61 
    62     //内部类
    63     class IteratorImpl<T> implements Iterator<T> {
    64 
    65         private int index = 0;
    66         MyList list = null;
    67 
    68         public IteratorImpl(MyList list)
    69         {
    70             this.list = list;
    71         }
    72 
    73         @Override
    74         public T next()
    75         {
    76             return (T) list.get(index++);
    77         }
    78 
    79         @Override
    80         public boolean hasNext()
    81         {
    82             boolean flag = false;
    83             if (list.get(index) != null)
    84             {
    85                 flag = true;
    86             }
    87             return flag;
    88         }
    89 
    90         @Override
    91         public void remove()
    92         {
    93             
    94         }
    95     }
    96 }

    同时,我们还可以使用简易for循环迭代这个聚合对象,如下:

     1 public class Test {
     2 
     3     public static void main(String[] args)
     4     {
     5         MyList<Apple> list = new MyList<Apple>();
     6         list.add(new Apple("a"));
     7         list.add(new Apple("b"));
     8 //        System.out.println(list.get(0));
     9 //        System.out.println(list.get(1));
    10 //        System.out.println(list.get(3));
    11         Iterator it = list.iterator();
    12         for(Apple a : list ){
    13             System.out.println(a);
    14         }
    15     }
    16 }

    结果与之前没有什么不同。

  • 相关阅读:
    第七十一课 图的定义与操作
    第七十课 二叉树经典面试题分析
    第六十九课 二叉树的线索化实现
    第六十八课 二叉树的比较与相加
    第六十七课 二叉树的典型遍历方式
    第六十六课 二叉树结构的层次遍历
    第六十五课 二叉树中属性操作的实现
    2018华为笔试题
    交错01串
    操作序列(网易)
  • 原文地址:https://www.cnblogs.com/zrtqsk/p/3716173.html
Copyright © 2011-2022 走看看