设计模式之迭代器与组合模式(一)
很高兴,这本书总共13章,这次已经是到第9章了;同时也很遗憾,小编脱离了书本,还是不知道如何描述一个设计模式。就比如迭代器与组合模式,原书篇幅比较长,小编尽量通俗易懂些,不到之处,还请各位小伙伴参考原书,小编也欢迎和大家一起交流。
有许多种方法可以把对象堆起来成为一个集合(collection)。你可以把它们放进数组、堆栈、列表或是散列表中,这是你的自由。每一种都有它自己的优点和适合的使用时机,但如果你想要遍历这些对象,怎么办呢?不用担心,接下来的学习就是如何能让客户遍历你的对象而又无法窥视你存储对象的方式;也将学习如何创建一些对象超集合,能够一口气就跳过某些让人望而生畏的数据结构。
对象村餐厅和对象村煎饼屋合并了
在面向对象的世界里,小伙伴们都开心的不要不要的,因为现在他们可以在同一个地方,享受煎饼屋美味的煎饼早餐,和好吃的餐厅午餐了。但是,有一点小麻烦......
煎饼屋记录的菜单项是使用数组来存储的,而餐厅是使用ArrayList记录他的菜单项,两家店长都不愿意改变现在的实现,毕竟有太多的代码依赖了,而我们又想减少依赖,用最小的改动。
两种表现形式会带来什么问题
想了解为什么有两种不同的菜单表现方式会让事情变得复杂化,让我们试着实现一个同时使用这两个菜单的客户代码。
我们新聘请了一位服务员,能应对顾客的需要打印定制的菜单,甚至告诉你是否某个菜单项是素食的,而无需询问厨师。要求如下:
- printMenu():打印出菜单上的每一项
- printBreakfastMenu():值打印早餐项
- printLunchMenu():只打印午餐项
- printVegetarianMenu():打印所有的素食菜单项
- isItemVegetarian(name):指定项的名称,如果该项是素食的话,返回true,否则返回false
实现上来说,如下所示:
- 打印每份菜单上的所有项,必须调用PancakeHouseMenu和DinerMenu的getMenuItem()方法,来取得它们各自的带单项
PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
ArrayList breakfastItems = pancakeHouseMenu.getMenuItems();
DinerMenu dinerMenu = new DinerMenu();
MenuItem[] lunchItems = dinerMenu.getMenuItems();
- 现在,分别打印里面的具体项目,早餐使用ArrayList,午餐使用数组
for (int i = 0; i < breakfastItems.size(); i++) {
MenuItem menuItem = (MenuItem)breakfastItems.get(i);
System.out.print(menuItem.getName());
System.out.println("\t\t" + menuItem.getPrice());
System.out.println("\t" + menuItem.getDescription());
}
for (int i = 0; i < lunchItems.length; i++) {
MenuItem menuItem = lunchItems[i];
System.out.print(menuItem.getName());
System.out.println("\t\t" + menuItem.getPrice());
System.out.println("\t" + menuItem.getDescription());
}
- 实现其他方法,做法也都和这一页的方法相类似。我们总是需要处理两个菜单,并且用两个循环遍历这些项。如果还有第三家餐厅以不同的实现出现,我们就需要有三个循环。
下一步怎么办?
他们都不想改变自身的实现,因为意味着要重写许多代码。所以,如果我们能够找出一个方法,让他们的菜单实现一个相同的接口,这该多好呢。我们试试看封装。
这本书给我们最大的改变,就是封装变化的部分。在这里发生的变化是:由不同的集合类型所造成的遍历。能被封装吗?我们继续来分析下:
- 要遍历早餐项,我们需要使用ArrayList的size()和get()方法
for(int i = 0; i < breakfastItems.size(); i++) {
MenuItem menuItem = (MenuItem)breakfastItems.get(i);
}
- 要遍历午餐项,我们需要使用数组的length字段和中括号
for (int i = 0; i < lunchItems.length; i++) {
MenuItem menuItem = lunchItems[i];
}
- 现在我们创建一个对象,我们把它称为迭代器(Iterator),利用它来封装“遍历集合内的每个对象的过程”
Iterator iterator = breakfastMenu.createIterator();
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
}
- 将它在数组上试试:
Iterator iterator = lunchMenu.createIterator();
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
}
看到这里,可以看到,我们对遍历的封装已经奏效了;你大概已经猜到,这正是一个设计模式,称为迭代器模式。那我们放在下次来具体说说,等着噢。
爱生活,爱学习,爱感悟,爱挨踢