简述-迭代器模式

介绍

一个容器,必然会涉及到遍历算法,如果将它封装在容器中,则增加了复杂度,如果客户实现,则不那么方便。所以引入第三方类来帮忙处理,这个类就是迭代器。

又称为游标模式,行为型设计模式之一。我的理解是目的在遍历,弱化容器与遍历算法的关系。在容器与访问类中添加一个迭代器,用于承担遍历,又不需要访问类自行实现。提供一种顺序访问一个容器对象中的各个元素,而又不需要暴露改对象的内部表示。

Android中数据库cusor则使用到了该模式。各个语言一般都有各自的迭代器实现,开发中很少会自己去实现迭代器了。

UML

组成结构

  • Iterator:迭代器接口,负责定义、访问、遍历元素的接口
  • ConcreteIterator:具体迭代器类,实现迭代器接口,并记录当前位置。
  • Aggregate:容器接口,负责提供创建迭代器角色的接口
  • ConcreteAggregate:具体容器类,具体迭代器角色与该容易相关联

使用场景

  • 遍历一个容器对象时

事例

比如有两个北鼻,他们喜欢的水果不同,咱们想遍历问问她们喜欢的水果,先看看不用迭代器的方式:

  1. 建立一个水果对象,用于承载。简易北鼻1和北鼻2对象,她们其中都有自己喜欢的水果列表持有,一个是以数组方式,一个是以列表方式,并提供获取数组和列表的方法:
/**
 * 水果
 */
public class ITeFruit {
    /**
     * 水果名称
     */
    private String name;

    public ITeFruit(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "ITeFruit{" +
                "name='" + name + '\'' +
                '}';
    }
}

/**
 * 北鼻1水果
 */
public class Beibi1Fruit {
    private List<ITeFruit> iTeFruits = new ArrayList<>();

    public Beibi1Fruit() {
        iTeFruits.add(new ITeFruit("菠萝"));
        iTeFruits.add(new ITeFruit("香蕉"));
        iTeFruits.add(new ITeFruit("哈密瓜"));
        iTeFruits.add(new ITeFruit("榴莲"));
        iTeFruits.add(new ITeFruit("火龙果"));
    }
    
    public List<ITeFruit> getiTeFruits(){
        return iTeFruits;
    }
}

/**
 * 北鼻二喜欢的水果
 */
public class Beibi2Fruit {
    private ITeFruit[] beibi2 = new ITeFruit[4];

    public Beibi2Fruit() {
        beibi2[0] = new ITeFruit("苹果");
        beibi2[1] = new ITeFruit("梨子");
        beibi2[2] = new ITeFruit("芒果");
        beibi2[3] = new ITeFruit("哈密瓜");
    }

    /**
     * 获取北鼻二喜欢的水果数组
     *
     * @return 水果数组
     */
    public ITeFruit[] getBeibi2Fruits() {
        return this.beibi2;
    }
}
  1. 进行遍历查询(这个没用增强for循环,那样看就没区别了):
//北鼻1,遍历
        Beibi1Fruit beibi1Fruit = new Beibi1Fruit();
        List<ITeFruit> iTeFruits = beibi1Fruit.getiTeFruits();
        System.out.println("北鼻一喜欢水果:");
        for (int i = 0; i < iTeFruits.size(); i++) {
            System.out.println(iTeFruits.get(i));
        }

        //北鼻2,遍历
        Beibi2Fruit beibi2Fruit = new Beibi2Fruit();
        ITeFruit[] beibi2Fruits = beibi2Fruit.getBeibi2Fruits();
        System.out.println("北鼻二喜欢水果:");
        for (int i = 0; i < beibi2Fruits.length; i++) {
            System.out.println(beibi2Fruits[i]);
        }

输出就不贴了,从这里就能看到,遍历两个的水果,使用的方式是不一样的,那么对外界来说得知道每个的遍历方式,相对麻烦了,那么就引入了,提供一个迭代器来实现。

  1. 建立一个迭代器接口,提供获取下一对象和是否还有下一个的方法:
/**
 * 迭代器接口
 */
public interface IteratorF {
    /**
     * 是否还有下一个
     *
     * @return
     */
    boolean hasNext();

    /**
     * 下一个
     *
     * @return 有则返回下一个对象,否则返回null
     */
    Object next();
}
  1. 创建北鼻1和北鼻2的迭代器,其中各自实现迭代方法:
/**
 * 北鼻1的迭代器
 */
public class Beibi1Iterator implements IteratorF {
    private List<ITeFruit> iTeFruits = new ArrayList<>();

    private int position;

    public Beibi1Iterator(List<ITeFruit> iTeFruits) {
        this.iTeFruits = iTeFruits;
    }


    @Override
    public boolean hasNext() {
        //如果列表中有个数且当前position还没到末尾
        return (iTeFruits.size() > 0 && position <= iTeFruits.size() - 1);
    }

    @Override
    public Object next() {
        //获取一个水果,然后将position+1
        return iTeFruits.get(position++);
    }
}

/**
 * 北鼻2的迭代器
 */
public class Beibi2Iterator implements IteratorF {
    private ITeFruit[] beibi2 = new ITeFruit[4];

    private int position;

    public Beibi2Iterator(ITeFruit[] beibi2) {
        this.beibi2 = beibi2;
    }


    @Override
    public boolean hasNext() {
        //如果数组中有个数且当前position还没到末尾
        return (beibi2.length > 0 && position <= beibi2.length - 1);
    }

    @Override
    public Object next() {
        //获取一个水果,然后将position+1
        return beibi2[position++];
    }
}
  1. 创建容器接口,提供一个获取迭代器的方法(这里简单点,就只提供下获取迭代器):
/**
 * 容器接口,该接口返回一个迭代器,由容器来实现
 */
public interface Aggregate {
    /**
     * 返回一个迭代器
     *
     * @return 迭代器
     */
    IteratorF iterator();
}
  1. 容器实现迭代器方法:
/**
 * 北鼻1水果
 */
public class Beibi1Fruit implements Aggregate {

    private List<ITeFruit> iTeFruits = new ArrayList<>();

    public Beibi1Fruit() {
        iTeFruits.add(new ITeFruit("菠萝"));
        iTeFruits.add(new ITeFruit("香蕉"));
        iTeFruits.add(new ITeFruit("哈密瓜"));
        iTeFruits.add(new ITeFruit("榴莲"));
        iTeFruits.add(new ITeFruit("火龙果"));
    }

    /**
     * 创建一个迭代器并返回
     *
     * @return
     */
    @Override
    public IteratorF iterator() {
        return new Beibi1Iterator(this.iTeFruits);
    }
}

/**
 * 北鼻二喜欢的水果
 */
public class Beibi2Fruit implements Aggregate {
    private ITeFruit[] beibi2 = new ITeFruit[4];

    public Beibi2Fruit() {
        beibi2[0] = new ITeFruit("苹果");
        beibi2[1] = new ITeFruit("梨子");
        beibi2[2] = new ITeFruit("芒果");
        beibi2[3] = new ITeFruit("哈密瓜");
    }
    
    @Override
    public IteratorF iterator() {
        return new Beibi2Iterator(this.beibi2);
    }
}
  1. 遍历:
//北鼻1,遍历
        Beibi1Fruit beibi1Fruit = new Beibi1Fruit();
        IteratorF iterator1 = beibi1Fruit.iterator();

        System.out.println("北鼻一喜欢水果:");
        while (iterator1.hasNext()) {
            System.out.println(iterator1.next());
        }

        //北鼻2,遍历
        Beibi2Fruit beibi2Fruit = new Beibi2Fruit();
        IteratorF iterator2 = beibi2Fruit.iterator();
        System.out.println("北鼻二喜欢水果:");
        while (iterator2.hasNext()) {
            System.out.println(iterator2.next());
        }

输出和第一步是一样的,但是看到遍历的地方了吗?这样子遍历就完全一样了,对使用方来说就非常方便了。

优缺点

优点
  • 自身优点单一,非常满足单一职责原则。
缺点
  • 对类文件的增加

总结:这个设计模式虽然平时我们一般比较少主动去使用,是因为库中已经有了,但是它遍历的设计思想,提供给客户的方便,内部的单一职责原则,是非常值得借鉴的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值