当前位置: 移动技术网 > IT编程>软件设计>设计模式 > 行为型模式:迭代器模式

行为型模式:迭代器模式

2019年03月01日  | 移动技术网IT编程  | 我要评论

liebrother原文
行为型模式:迭代器模式

景

十一大行为型模式之六:迭代器模式。

简介

姓名 :迭代器模式

英文名 :iterator pattern

价值观 :人生没有回头路

个人介绍

provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
它提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。
(来自《设计模式之禅》)

你要的故事

大家伙听歌频率高么?是不是经常听歌曲来放松心情?我是经常会听歌,心情不好的时候听歌,心情好的时候也听歌。。。今天讲的迭代器模式,我们就拿听歌这件事来说说,大家都知道听歌有几种模式:单曲循环、列表循环、随机等等。。。现在网易云音乐还多了一个心动模式。

既然说到迭代器模式,那这里就要着重讲讲列表循环这个听歌模式,其他的就先抛到脑后。在列表循环中,歌曲从第一条播放到最后一条,也就是一个遍历歌单的过程。我们有 2 种实现方式,一种是没有迭代器,通过获取歌单,用 for 循环遍历每一个歌曲,然后播放;另外一种是使用迭代器,获取歌单的一个迭代器,通过迭代器来遍历每一个歌曲,然后播放。下面我们就用代码来实现这 2 种方式。

木有迭代器

public class noiteratortest {

    public static void main(string[] args) {
        neteasemusic1 neteasemusic1 = new neteasemusic1();
        neteasemusic1.listentomusicbyloop();
    }
}

/**
 * 网易云音乐
 */
class neteasemusic1 {

    private ilist1 songlist;

    public neteasemusic1() {
        songlist = new songlist1(3);
        songlist.add(new song("让我留在你身边", "陈奕迅"));
        songlist.add(new song("你曾是少年", "she"));
        songlist.add(new song("perfect", "ed sheeran"));
    }

    /**
     * 列表循环
     */
    public void listentomusicbyloop() {
        for (int i = 0; i < songlist.size(); i++) {
            system.out.println("听歌:" + ((isong)songlist.get(i)).getsonginfo());
        }
    }

}

/**
 * 容器接口
 */
interface ilist1 {

    void add(object object);

    object get(int index);

    int size();
}

/**
 * 歌单
 */
class songlist1 implements ilist1 {

    private isong[] songs;
    private int index;
    private int size;

    public songlist1(int size) {
        songs = new isong[size];
        index = 0;
        size = 0;
    }

    @override
    public void add(object object) {
        songs[index++] = (isong) object;
        size ++;
    }

    @override
    public object get(int index) {
        if (index < size) {
            return songs[index];
        }
        return null;
    }

    @override
    public int size() {
        return size;
    }
}


/**
 * 歌曲接口
 */
interface isong {
    string getsonginfo();
}

/**
 * 歌曲
 */
class song implements isong{

    private string name;
    private string singer;

    public song(string name, string singer) {
        this.name = name;
        this.singer = singer;
    }

    @override
    public string getsonginfo() {
        return this.name + "--" + this.singer;
    }

    public string getname() {
        return name;
    }

    public void setname(string name) {
        this.name = name;
    }

    public string getsinger() {
        return singer;
    }

    public void setsinger(string singer) {
        this.singer = singer;
    }

}

打印结果:
听歌:让我留在你身边--陈奕迅
听歌:你曾是少年--she
听歌:perfect--ed sheeran

我们定义了 isong 接口,里面有个 getsonginfo() 方法来获取歌曲信息,用 song 类来定义歌曲。没有用 java 自带的容器来存放歌曲,这里实现了一个自定义容器接口 ilist1,定义 songlist1 来做歌曲的容器,为什么不用 java 自带的 arraylist 等等?因为 java 自带的已经实现了迭代器功能了,我们这里自定义其实就是在模仿自带的容器的实现。neteasemusic1 类是充当网易云音乐客户端,在 listentomusicbyloop() 方法中,我们可以看到是获取了歌单 songlist,然后一个一个遍历,这是没有使用迭代器的代码。

下面看一下使用迭代器的代码是怎么样的。

用迭代器实现遍历

public class iteratortest {

    public static void main(string[] args) {
        neteasemusic2 neteasemusic2 = new neteasemusic2();
        neteasemusic2.listentomusicbyloop();
    }

}

/**
 * 网易云音乐
 */
class neteasemusic2{

    private ilist2 songlist;

    public neteasemusic2() {
        songlist = new songlist2(3);
        songlist.add(new song("让我留在你身边", "陈奕迅"));
        songlist.add(new song("你曾是少年", "she"));
        songlist.add(new song("perfect", "ed sheeran"));
    }

    /**
     * 列表循环
     */
    public void listentomusicbyloop() {
        iiterator iterator = songlist.iterator();
        while (iterator.hasnext()) {
            system.out.println("听歌:" + ((isong)iterator.next()).getsonginfo());
        }

    }

}

/**
 * 容器接口
 */
interface ilist2 {

    iiterator iterator();

    void add(object object);

    object get(int index);

    int size();
}

/**
 * 歌单
 */
class songlist2 implements ilist2 {

    private isong[] songs;
    private int index;
    private int size;

    public songlist2(int size) {
        songs = new isong[size];
        index = 0;
        size = 0;
    }

    @override
    public iiterator iterator() {
        return new iteratorimpl(this);
    }

    @override
    public void add(object object) {
        songs[index++] = (isong) object;
        size ++;
    }

    @override
    public object get(int index) {
        if (index < size) {
            return songs[index];
        }
        return null;
    }

    @override
    public int size() {
        return size;
    }
}


/**
 * 迭代器
 */
interface iiterator {
    object next();
    boolean hasnext();
}

/**
 * 迭代器实现类
 */
class iteratorimpl implements iiterator {

    private ilist2 list;
    private int index;

    public iteratorimpl(ilist2 list) {
        this.list = list;
        this.index = 0;
    }

    @override
    public object next() {
        return list.get(index++);
    }

    @override
    public boolean hasnext() {
        if (index < list.size()) {
            return true;
        }
        return false;
    }
}

打印结果:
听歌:让我留在你身边--陈奕迅
听歌:你曾是少年--she
听歌:perfect--ed sheeran

代码中我们自定义了一个迭代器接口 iiterator 和迭代器具体实现类 iteratorimpl,有关键的 2 个方法,hasnext() 判断是否有存在下一个元素,next() 获取下一个元素。而 ilist2 接口则比 ilist1 接口多了一个获取迭代器的方法 iterator(),这让网易云音乐在遍历歌单的时候,不用直接使用 songlist 来遍历,而可以通过 songlist.iterator() 获取迭代器来实现遍历的过程。neteasemusic2.listentomusicbyloop() 这个方法里面就直接获取迭代器来遍历了。

代码:
iterator pattern

总结

迭代器模式是所有设计模式中使用最广泛的,有不少开发同学知道迭代器,但是不知道它是设计模式的。虽然迭代器的代码会比没有迭代器的代码复杂,但是加上迭代器可以让容器有统一的遍历代码风格,不用各自去实现遍历方法,有更好的封装性。在 java 中,迭代器已经运用很广泛,比如 java 中访问 mysql 获取数据就是用迭代器来遍历数据的。好了,迭代器模式就讲到这,大家知道的知识就不多说啦。

参考资料:《大话设计模式》、《设计模式之禅》

推荐阅读:

行为型模式:策略模式

行为型模式:责任链模式

行为型模式:命令模式

希望文章对您有所帮助,设计模式系列会持续更新,感兴趣的同学可以关注公众号:liebrother,第一时间获取文章推送阅读,也可以一起交流,交个朋友。

公众号

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网