设计模式(2)--迭代器(Iterator)

这次笔者写写设计模式中较为简单的一个设计模式–Iterator(迭代器),为什么说它简单呢?主要的原因是它仅仅是用在了对于容器的遍历上。一般来说,一个及格的Programmer(程序员,注:Programmer != Coder,Coder是码农,其较之Programmer的层次低很多而且是一种蔑称,适用于自嘲但不适用于被人贴标签,此仅代表笔者的个人观点),都应该知道不同的数据结构之间(或者是不同容器之间)所使用到对内部存储数据访问的方式是不同的,即少有类似的遍历方式存在。譬如:数组的遍历是通过下标访问的方式、链表通过指针(或引用)访问的方式遍历、栈通过弹栈的方式遍历(虽然栈在正常情况下是不会进行遍历的)等等。
回到我们之前问题的回答上,由于它仅仅是用在了对于容器的遍历上我们说它简单,这里所说的简单并不是说它的实现简单(当然如果仅仅是list的话还是不会很难的,但是你可以试试对map的实现,呵呵!)而是说它在这么多的设计模式中没有那么复杂应用,比如笔者上一篇所写的Dynamic Proxy,它的应用面就太广了,就Spring来说对它的应用就足够初学的研究一段时间了。
现在我们来想想,我们为什么要用这种设计模式?它能带来什么样的便利?
笔者是这么想的:因为容器的遍历方式是各种各样的,为了减轻使用者的负担,我们应该想办法让它们统一起来,这样的统一应该是调用时的统一而不是实现方式的统一,实现过程对于使用来说应该是屏蔽的(黑盒),这样使用者就不用去纠结实现细节了。
在实现设计模式时需要经过几个版本的迭代,代码较多,主要是为了把思路体现出来。

1.Design a container of ArrayList & LinkedList(code version1.0)

现在笔者分别手写一个ArrayList和LinkedList的实现,ArrayList是基于数组实现的,LinkedList是基于链表实现的。

ArrayList.java

public class ArrayList{
    private Object[] obj = new Object[5];
    private int index = 0;

    public void add(Object o){
        if(index >= obj.length){
            Object[] tmp = new Object[index + 20];
            System.arraycopy(obj, 0, tmp, 0, obj.length);
            obj = tmp;
        }
        obj[index++] = o;
    }

    public int size(){
        return index;
    }

}

特别地说下,链表的实现需要先构建一个Node类。

Node.java

public class Node{
    private Object data;
    private Node next;

    public Node(Object data, Node next){
        this.data = data;
        this.next = next;
    }

    public void setData(Object data){
        this.data = data;
    }

    public Object getData(){
        return data;
    }

    public void setNext(Node next){
        this.next = next;
    }

    public Node getNode(){
        return next;
    }
}

LinkedList.java

public class LinkedList{
    private Node head = null;
    private Node tail = null;
    private int index = 0;//冗余的数据来加强性能

    public void add(Object o){
        Node n = new Node(o, null);//创建新的节点
        if(null == head){
            head = n;
            tail = n;
        }

        tail.setNext(n);
        tail = n;
        index++;
    }

    public int size(){
        return index;
    }
}

以上就是自己实现的可以动态存放对象的两类容器。

2.How to traverse the elements in container(code version1.1)

可以看到笔者对于上面的实现是只对元素的添加做了方法处理,并不能做获取元素的方法处理。那我们开始想想应该如何遍历获取这些元素。
通常我们对于数组的元素获取多是通过下标的方式,链表的则是通过获取链表的头部逐个逐个地访问获取。这种思路并没有太多的创新的地方,因为一旦我们需要考虑起方法的复用时我们该怎么办?各种各样的实现我们明显是做不到对方法中的实现进行复用的,那我们换个思路,我们改成对方法这个入口的复用不就好了么!我们只要设计成一个接口让具体的类进行实现,这样就能做到黑盒了!

Iterator.java

public interface Iterator{
    boolean hasNext();
    Object next();
}

ArrayList.java

public class ArrayList{

    private Object[] obj = new Object[5];
    private int index = 0;
    private Iterator l = new ArrayListIterator();//这样有singleton(单例设计)的味道

    public void add(Object o){
        if(index == obj.length){
            Object[] tmp = new Object[index + 20];
            System.arraycopy(obj, 0, tmp, 0, obj.length);
            obj = tmp;
        }
       obj[index++] = o;
    }

    public int size(){
        return index;
    }

    public Iterator iterator() {
        return l;
    }

    //使用内部类可以访问外部类的数据成员
    private class ArrayListIterator implements Iterator{

        private int currentIndex = 0;

        @Override
        public boolean hasNext() {
            if(this.currentIndex >= index) return false;
            return true;
        }

        @Override
        public Object next() {
           return obj[currentIndex++];
        }
    }


}

LinkedList.java

public class LinkedList{
    private Node head = null;
    private Node tail = null;
    private int index = 0;//冗余的数据来加强性能
    private LinkedListIterator l = new LinkedListIterator();

    public void add(Object o){
        Node n = new Node(o, null);//创建新的节点
        if(null == head){
            head = n;
            tail = n;
        }

        tail.setNext(n);
        tail = n;
        index++;
    }

    public int size(){
        return index;
    }

    public Iterator iterator() {
        return l;
    }

    private class LinkedListIterator implements Iterator{

        private int currentIndex = 0;
        private Node currentTarObj = null;

        @Override
        public boolean hasNext() {
            if(currentIndex >= index) return false;
            return true;
        }

        @Override
        public Object next() {
            if(null == head) return null;

            if(0 == currentIndex){
                currentTarObj = head;
            } else {
               currentTarObj = currentTarObj.getNext();
            }
            currentIndex++;
            return currentTarObj.getData();
        }
    }

}

Test.java

public class Test{
    public static void main(String[] args){
        ArrayList arr = new ArrayList();
        for (int i = 0; i < 26; i++) {
            arr.add(i);
        }
        System.out.println("arrayList size: " + arr.size());
        Iterator itr1 = arr.iterator();
        while (itr1.hasNext()){
            System.out.print(itr1.next() + " ");
        }
        System.out.println();

        LinkedList ll = new LinkedList();
        for (int i = 0; i < 10; i++) {
            ll.add(i);
        }
        System.out.println("linkedlist size: " + ll.size());
        Iterator itr2 = ll.iterator();
        while (itr2.hasNext()){
            System.out.print(itr2.next() + " ");
        }
    }
}

3.Continue to optimize(code version1.2)

仔细看上面的代码,我们很容易发现,ArrayList和LinkedList其实方法基本是一样的,一样的东西我们就可以考虑说能否把它们抽象出来成为接口。
当然你可能说这是笔者有意设置,但是你想想如果它们要实现的动作是差不多的,为什么我们不能考虑统一的命名规范呢?杂乱很可能在未来带来你我无法想象维护困难,难道不是吗?(再说了,如果未来如果是被你所知那还能称为未来吗?我们的想法最多算是猜测,再多的规划也不是一定会实现的,若说大势所趋就是未来,那么随着大势而去也难保总有人会葬送在这潮流中,这葬送的人中有你我吗?)
现在笔者来做一个稍高一点层次的抽象,让ArrayList和LinkedList成为这个抽象的一种具体实现而已,这也说明一个颠覆性的观点:从特殊推导出一般

Collection.java

public interface Collection{
    void add(Object o);
    int size();
    Iterator iterator();
}

ArrayList.java

public class ArrayList implements Collection{

    private Object[] obj = new Object[5];
    private int index = 0;
    private Iterator l = new ArrayListIterator();//这样有singleton(单例设计)的味道

    @Override
    public void add(Object o){
        if(index == obj.length){
            Object[] tmp = new Object[index + 20];
            System.arraycopy(obj, 0, tmp, 0, obj.length);
            obj = tmp;
        }
       obj[index++] = o;
    }

    @Override
    public int size(){
        return index;
    }

    @Override
    public Iterator iterator() {
        return l;
    }

    //使用内部类可以访问外部类的数据成员
    private class ArrayListIterator implements Iterator{

        private int currentIndex = 0;

        @Override
        public boolean hasNext() {
            if(this.currentIndex >= index) return false;
            return true;
        }

        @Override
        public Object next() {
           return obj[currentIndex++];
        }
    }


}

LinkedList.java

public class LinkedList implements Collection{
    private Node head = null;
    private Node tail = null;
    private int index = 0;//冗余的数据来加强性能
    private LinkedListIterator l = new LinkedListIterator();

    @Override
    public void add(Object o){
        Node n = new Node(o, null);//创建新的节点
        if(null == head){
            head = n;
            tail = n;
        }

        tail.setNext(n);
        tail = n;
        index++;
    }

    @Override
    public int size(){
        return index;
    }

    @Override
    public Iterator iterator() {
        return l;
    }

    private class LinkedListIterator implements Iterator{

        private int currentIndex = 0;
        private Node currentTarObj = null;

        @Override
        public boolean hasNext() {
            if(currentIndex >= index) return false;
            return true;
        }

        @Override
        public Object next() {
            if(null == head) return null;

            if(0 == currentIndex){
                currentTarObj = head;
            } else {
               currentTarObj = currentTarObj.getNext();
            }
            currentIndex++;
            return currentTarObj.getData();
        }
    }

}

Test.java

public class Test{
    public static void main(String[] args){
        Collection arr = new ArrayList();
        for (int i = 0; i < 26; i++) {
            arr.add(i);
        }
        System.out.println("arrayList size: " + arr.size());
        Iterator itr1 = arr.iterator();
        while (itr1.hasNext()){
            System.out.print(itr1.next() + " ");
        }
        System.out.println();

        Collection ll = new LinkedList();
        for (int i = 0; i < 10; i++) {
            ll.add(i);
        }
        System.out.println("linkedlist size: " + ll.size());
        Iterator itr2 = ll.iterator();
        while (itr2.hasNext()){
            System.out.print(itr2.next() + " ");
        }
    }
}

这里写图片描述
这样我们不仅实现了方法复用,还实现了容器的可替换。
笔者这次就i到此为止了!
感谢各位的支持!
如果note有错漏,恳请各位留下评论指出,笔者会及时改正!
谢谢!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值