设计模式入门——迭代器模式

背景:

两个餐厅要合并啦,但是一家餐厅菜单用的是数组,另一家用的是ArrayList,两家餐厅都不想改自己的代码,因为牵一发动全身。

方案一:用一个新的菜单,将原有的两个菜单写到里面,用两个不同的循环去便利

不可行:万一再加一个菜单,是不是还要继续遍历,这样代码将难以维护、难以扩展。其次新的菜单需要知道每个菜单如何表达(如何遍历),违反了封装。

设计:

我们应该针对接口编程,而不是针对具体实现编程。我们看到大家用在遍历,只是遍历的方式不同,所以我们需要对此进行封装。

单一责任原则:一个类应该只有一个引起变化的原因。

优点:逆向思维,如果我们允许聚合实现他们内部集合,以及相关的操作遍历的方法,这就代表一个类有两个变化,如果这个类集合改变,则类需改变,如果遍历方法改变,则类也必须改变。我们需要避免类内的改变,类的每个责任都有改变的潜在区域,超过一个责任,意味着超过一个改变的区域,所以我们需要尽量让每个类保持单一责任。

当一个模块或者类被设计为只支持一组相关的功能时,我们说它具有高内聚;反之,当被设计成支持一组不相关的功能时,我们说它具有低内聚。内聚是一个比单一责任原则更加普遍的概念,两者的关系十分密切,遵循这个原则的类容易实现很高的凝聚力,更加容易维护。

实现:

// 迭代器接口,虽然Java已经有了
public interface Iterator {
    boolean hasNext();
    Object next();    
}
// 实现据类的迭代器,为餐厅菜单服务
public class DinerMenuIterator implements Iterator {
    MenuItem[] items;
    int position = 0;   // 记录当前数组遍历的位置

    public DinnerMenuIterator(MenuItem[] items){
        this.items = items;    
    }
    
    public Object next() {
        MenuItem menuItem = items[position];
        position++;
        return menuItem;
    }

    public boolean hasNext() {
        if(position >= items.length || items[position] == null){  // 数组是固定大小长度,所以要检查长度和是否为空
            return false;
        } else {
            return true;
        }
    }
}
// 菜单接口
public interface Menu {
    public Iterator createIterator();    
}
// 餐厅菜单    所有的菜单实现统一的接口
public class DinerMenu implements Menu {
    static final int MAX_ITEMS = 6;
    int numberOfItems = 0;
    MenuItem[] menuItems;

    ...

    // 用来从菜单项数组创建一个DinerMenuIterator,并将它返回给客户。
    public Iterator createIterator() {
        return new DinerMenuIterator(menuItems);
    }  
}
// 女服务员的代码
public class Waitress {
    PancakeHouseMenu pancakeHouseMenu; // 两个菜单  也可以用ArrayList打包多个菜单,这样就可以遍历输出,而不用一个一个输出
    DinerMenu dinerMenu;

    public Waitress(PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu) {
        this.pancakeHouseMenu = pancakeHouseMenu;
        this.dinerMenu = dinerMenu;
    }
    
    public void printMenu() {
        Iterator pancakeIterator = pancakeHouseMenu.createIterator();
        Iterator dinerIterator = dinerMenu.createIterator();
        printMenu(pancakeIterator);
        printMenu(dinerIterator);
    }
    
    // 遍历
    private void printMenu(Iterator iterator) {
        while(hasNext()) {
            MenuItem menuItem = (MenuItem)iterator.next();
            print(...)
        }
    }

}

女服务员可以利用接口而不是具体类引用每一个菜单对象。这样,通过“针对接口编程,而不针对实现编程”,我们就可以减少女服务员和具体类之间的依赖。女服务员只需关心菜单和迭代器两个接口即可。

总结:

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

  1. 迭代器模式给你提供了一种方法,可以顺序访问一个聚焦对象中的元素,而有不用知道内部是如何表示的。
  2. 迭代器模式把元素之间游走的责任交给迭代器,而不是聚合对象,这样简化了聚合的接口和实现,也让责任各得其所。

迭代器有内部迭代和外部迭代之分,内部迭代是指将操作传给迭代器,因为客户无法控制迭代器,所以内部迭代没有弹性。我们用的是外部迭代。

迭代器意味着没有次序,只是取出了所有元素。

现在遍历Collection,可以用for/in,更加方便。

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值