设计模式(十)几段代码搞懂迭代器模式

关于迭代器模式的定义,我就直接引用Head First了:迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。这里的聚合就是我们常说的集合,迭代器模式能让我们遍历集合内的对象,而又无需暴露集合本身的存储结构(如数组,链表,散列表等),把遍历的任务封装起来,放在迭代器对象上,使其与集合所在的对象解耦。那为何要将遍历的部分封装起来?其目的是为了让类的职责变得单一,让集合能更专注于自身职责的处理。具体看下:

迭代器模式

假如厂商有两款智能设备产品,为:智能音箱和智能空调,现厂商决定要打造智能生态系统,需要将两款智能设备的用户整合到一起。但由于两个部门对于数据处理模块都有着各自的考量,所以让本次的合并困难重重(一个是List,一个是数组,两者的接口方法不一致)

这是当前的智能音箱类

public class SpeakerBox {
    ArrayList<User> users = new ArrayList();

    public void register(User user) {
        users.add(user);
    }
    public ArrayList getUsers() {
        return users;
    }
    /**
     * 当然内部还有很多复杂的逻辑处理,
     * 都依赖于此ArrayList容器,
     * 导致无法轻易更改存储结构。
     */
}

这是当前的智能空调类

public class AirConditioner {
    static final int MAX_USER_COUNT = 100;
    User[] users = new User[MAX_USER_COUNT];
    int curItemCount = 0;

    public void register(User user) {
        if (curItemCount >= MAX_USER_COUNT)
            System.out.println("用户超额!");
        else {
            users[curItemCount] = user;
            curItemCount++;
        }
    }
    public User[] getUsers() {
        return users;
    }
}

这是用户信息类

public class User {
    private String ID;
    public String getId() {
        return ID;
    }
}

两部门老大经过一番商谈,最后决定将用户集合的迭代工作从各自的数据处理模块中抽离出来,让处理模块的职责更单一些,以达到降低耦合的目的。个人认为此处所说的“迭代” 只是迭代器模式的标准形式,其实不仅仅是迭代,我们还能抽离出很多其他的操作,如插首、插尾,甚至自定义的操作等。我觉得它的意图是给不同结构的集合,通过迭代器类,抽离出一套对外的统一的接口供用户使用,让用户无需关心所处理的集合的结构表示,只需要针对Iterator 编程就可以

这是两部门抽离出的迭代器接口类(当然也可以使用Java 自带的java.util.Iterator 适配器接口,这里就直接使用自定义的了)。

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

这是智能音箱部门实现的音箱适配器类

public class SpeakerBoxIterator implements Iterator {
    ArrayList<User> users;
    int curItemCount = 0;
    int size;
    public SpeakerBoxIterator(ArrayList<User> users) {
        this.users = users;
        if (null != this.users)
            size = this.users.size;
    }
    @Override public boolean hasNext() {
        return curItemCount < size;
    }
    @Override public Object next() {
        if (curItemCount >= size)
            return null;
        else {
            int cursor = curItemCount;
            curItemCount++;
            return users.get(cursor);
        }
    }
}

同理,这是智能空调部门实现的空调适配器类

public class AirConditionerIterator implements Iterator {
    User[] users;
    int curItemCount = 0;
    int length;
    public AirConditionerIterator(User[] users) {
        this.users = users;
        if (null != this.users)
            length = this.users.length;
    }
    @Override public boolean hasNext() {
        return curItemCount < length;
    }
    @Override public Object next() {
        if (curItemCount >= length)
            return null;
        else {
            int cursor = curItemCount;
            curItemCount++;
            return users[cursor];
        }
    }
}

有了适配器类之后,我们再改造下我们的智能音箱类2.0,能够看出,我们已经将迭代的责任移交给了 SpeakerBoxIterator 来处理,所以SpeakerBox 本身不需要再提供具体的迭代方法,也不需要对用户暴露自身的集合类型。

public class SpeakerBox {
    ArrayList<User> users = new ArrayList();

    public void register(User user) {
        users.add(user);
    }
    public Iterator creatIterator() {
        return new SpeakerBoxIterator(users);
    }
}

这是智能空调类2.0

public class AirConditioner {
    static final int MAX_USER_COUNT = 100;
    User[] users = new User[MAX_USER_COUNT];
    int curItemCount = 0;

    public void register(User user) {
        if (curItemCount >= MAX_USER_COUNT)
            System.out.println("用户超额!");
        else {
            users[curItemCount] = user;
            curItemCount++;
        }
    }
    public Iterator creatIterator() {
        return new AirConditionerIterator(users);
    }
}

这是我们的使用类,能够发现ClientTest 并不需要知道音箱和空调类内部集合的类型,只需要针对Iterator 编程即可,通过creatIterator 方法就能够遍历集合内的每个元素。

public class ClientTest {
    public static void main(String[] ags) {
        // 将智能音箱和空调的用户打印出来
        Iterator sbIterator = speakerBox.creatIterator();
        Iterator acIterator = airConditioner.creatIterator();
        printInfo(sbIterator);
        printInfo(acIterator);
    }
    private static void printInfo(Iterator iterator) {
        while (iterator.hasNext()) {
            User user = (User) iterator.next();
            System.out.println("用户ID: " + User.getId());
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章