文章目录
1 迭代器模式
1.1 来自餐厅的需求
现在有两家店要进行合并,一家是早餐店,一家是午餐店,他们有着各自的菜单,各自的招待员,每个菜单项记录:菜名,简介,是否为素食,价格
/**
* @author 雫
* @date 2021/3/9 - 11:35
* @function 菜单项
*/
public class MenuItem {
private String name;
private String description;
private boolean vegetarian;
private double price;
public MenuItem(String name, String description, boolean vegetarian, double price) {
this.name = name;
this.description = description;
this.vegetarian = vegetarian;
this.price = price;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public boolean isVegetarian() {
return vegetarian;
}
public double getPrice() {
return price;
}
}
这两家店采用相同的MenuItem,但是问题来了,他们采用了不同的集合,早餐店老板希望以后能扩展他的菜单,采用了ArrayList来封装MenuItem,午餐店老板希望能控制菜单的长度,采用了数组来封装MenuItem:
/**
* @author 雫
* @date 2021/3/9 - 11:39
* @function 早餐店的菜单
* 采用ArrayList封装MenuItem
*/
public class AMenu {
private ArrayList<MenuItem> menuItems;
public AMenu() {
this.menuItems = new ArrayList<>();
addItem("bread", "good bread", true, 7);
addItem("milk", "nice milk", true, 6);
addItem("burger", "good chickenBurger", false, 10);
}
public void addItem(String name, String description, boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
menuItems.add(menuItem);
}
public ArrayList<MenuItem> getMenuItems() {
return this.menuItems;
}
}
/**
* @author 雫
* @date 2021/3/9 - 11:44
* @function 午餐店菜单
* 采用数组封装MenuItem
*/
public class BMenu {
private static final int MAX_ITEMS = 6;
private int numberOfItems = 0;
private MenuItem[] menuItems;
public BMenu() {
menuItems = new MenuItem[MAX_ITEMS];
addItem("soup", "good soup", true, 20);
addItem("chicken", "nice chicken", false, 40);
addItem("juice", "good juice", true, 15);
}
public void addItem(String name, String description, boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
if(this.numberOfItems >= MAX_ITEMS) {
System.out.println("菜单已满");
} else {
menuItems[numberOfItems] = menuItem;
numberOfItems = numberOfItems + 1;
}
}
public MenuItem[] getMenuItems() {
return this.menuItems;
}
}
原先早餐店和午餐店各自经营,各有一个招待员,他们只用管理自己的列表/数组:
/**
* @author 雫
* @date 2021/3/9 - 12:04
* @function 早餐店招待员
*/
public class AWaiter {
private ArrayList<MenuItem> menuItems;
public AWaiter(ArrayList<MenuItem> menuItems) {
this.menuItems = menuItems;
}
public void printMenu() {
for(MenuItem m : menuItems) {
System.out.println(m.getName());
System.out.println(m.getDescription());
System.out.println(m.isVegetarian());
System.out.println(m.getPrice());
}
}
public void printVegetarian() {
for(MenuItem m : menuItems) {
if(m.isVegetarian()) {
System.out.println(m.getName());
System.out.println(m.getDescription());
System.out.println(m.isVegetarian());
System.out.println(m.getPrice());
}
}
}
public boolean isItemVegetarian(String name) {
for(MenuItem m : menuItems) {
if(name.equals(m.getName())) {
if(m.isVegetarian()) {
return true;
}
return false;
}
}
return false;
}
}
现在我们需要给合并后的餐厅设计一个招待员,用于管理两个集合,要求他能够实现如下功能:
1,打印出两个菜单上的每一项
2,只打印早餐店的菜单项
3,只打印午餐店的菜单项
4,打印所有的素食菜单项
5,指定菜名,如果是素食返回true,否则返回false
1.2 粗糙地设计一个招待员
我们先从功能1开始,粗糙地设计一个招待员,打印两个菜单上的所有项:
/**
* @author 雫
* @date 2021/3/9 - 12:21
* @function 合并后店铺的招待员
*/
public class Waiter {
private ArrayList<MenuItem> AmenuItems;
private MenuItem[] BmenuItems;
public Waiter(ArrayList<MenuItem> amenuItems, MenuItem[] bmenuItems) {
this.AmenuItems = amenuItems;
this.BmenuItems = bmenuItems;
}
public void print() {
for(int i = 0; i < AmenuItems.size(); i++) {
MenuItem m = AmenuItems.get(i);
System.out.println(m.getName() + ", " + m.getDescription()
+ ", " + m.isVegetarian() + ", " + m.getPrice());
}
for(int i = 0; i < this.BmenuItems.length; i++) {
MenuItem m = BmenuItems[i];
System.out.println(m.getName() + ", " + m.getDescription()
+ ", " + m.isVegetarian() + ", " + m.getPrice());
}
}
}
其它的功能若要实现,与上述的实现方式类似,都必须对两个菜单进行遍历处理,如果需要增加第三个菜单,就得遍历3次,以此类推
上述粗糙设计的招待员,存在如下问题:
1,针对实现编程,将功能和实现捆绑到一起
2,如果要增加新的菜单,就必须大面积更改源码,违反了开闭原则
3,招待员想要实现功能,就必须知道各个菜单集合的管理方式,违反了封装
并且早餐店和晚餐店的店主都不愿意更改自己的代码,那么上述实现的招待员变得难以维护,缺乏弹性,我们需要一种新的方式来管理不同的集合
1.3 创建自己的迭代器
回顾刚才遍历列表和数组的过程:
想要遍历列表,需要用到size()方法,想要遍历数组,需要用到length()方法,对于不同的集合需要不同的方法来遍历
现在我们创建一个接口,称为迭代器,其中的两个抽象方法用于遍历集合,为每种集合创建一个类实现该迭代器:
/**
* @author 雫
* @date 2021/3/9 - 13:09
* @function 迭代器接口
*/
public interface Iterator {
boolean hasNext();
Object next();
}
/**
* @author 雫
* @date 2021/3/9 - 13:10
* @function 早餐店菜单迭代器
*/
public class AMenuIterator implements Iterator {
private ArrayList<MenuItem> AMenuItems;
private int position = 0;
public AMenuIterator(ArrayList<MenuItem> AMenuItems) {
this.AMenuItems = AMenuItems;
}
@Override
public boolean hasNext() {
if(this.position >= AMenuItems.size() || this.AMenuItems.get(this.position) == null) {
return false;
} else {
return true;
}
}
@Override
public Object next() {
MenuItem menuItem = AMenuItems.get(this.position);
this.position = this.position + 1;
return menuItem;
}
}
/**
* @author 雫
* @date 2021/3/9 - 14:13
* @function 午餐店菜单迭代器
*/
public class BMenuIterator implements Iterator {
private MenuItem[] menuItems;
private int position;
public BMenuIterator(MenuItem[] menuItems) {
this.menuItems = menuItems;
}
@Override
public boolean hasNext() {
if(this.position >= menuItems.length || menuItems[this.position] == null) {
return false;
} else {
return true;
}
}
@Override
public Object next() {
MenuItem menuItem = menuItems[this.position];
this.position = this.position + 1;
return menuItem;
}
}
更改后的早餐店和午餐店:
/**
* @author 雫
* @date 2021/3/9 - 11:39
* @function 早餐店的菜单
* 采用ArrayList封装MenuItem
*/
public class AMenu {
private ArrayList<MenuItem> menuItems;
public AMenu() {
this.menuItems = new ArrayList<>();
addItem("bread", "good bread", true, 7);
addItem("milk", "nice milk", true, 6);
addItem("burger", "good chickenBurger", false, 10);
}
public void addItem(String name, String description, boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
menuItems.add(menuItem);
}
public Iterator createIterator() {
return new AMenuIterator(this.menuItems);
}
}
/**
* @author 雫
* @date 2021/3/9 - 11:44
* @function 午餐店菜单
* 采用数组封装MenuItem
*/
public class BMenu {
private static final int MAX_ITEMS = 3;
private int numberOfItems = 0;
private MenuItem[] menuItems;
public BMenu() {
menuItems = new MenuItem[MAX_ITEMS];
addItem("soup", "good soup", true, 20);
addItem("chicken", "nice chicken", false, 40);
addItem("juice", "good juice", true, 15);
}
public void addItem(String name, String description, boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
if(this.numberOfItems >= MAX_ITEMS) {
System.out.println("菜单已满");
} else {
menuItems[numberOfItems] = menuItem;
numberOfItems = numberOfItems + 1;
}
}
public Iterator createIterator() {
return new BMenuIterator(this.menuItems);
}
}
更改后的招待:
/**
* @author 雫
* @date 2021/3/9 - 12:21
* @function 使用迭代器的招待员
*/
public class Waiter {
private AMenu aMenu;
private BMenu bMenu;
public Waiter(AMenu aMenu, BMenu bMenu) {
this.aMenu = aMenu;
this.bMenu = bMenu;
}
public void printAll() {
Iterator aIterator = this.aMenu.createIterator();
Iterator bIterator = this.bMenu.createIterator();
printMenu(aIterator);
printMenu(bIterator);
}
public void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
System.out.println(menuItem.getName() + ", " + menuItem.getDescription()
+ ", " + menuItem.isVegetarian() + ", " + menuItem.getPrice());
}
}
}
测试:
使用迭代器设计的招待员特点:
1,菜单的实现被封装了起来,招待员并不知道菜单集合地实现
2,只需要一个循环,就可以多态地处理不同集合
但现在招待员依赖两个菜单对象,我们需要更进一步地设计,采用依赖倒置原则,将招待员解耦出来,让系统更具有弹性
1.4 使用java.util.Iterator
Java中有一个Iterator接口,就是专门用来为集合创建具体的迭代器:
除了hasNext()和next()方法外,还有一个remove()方法允许我们从集合中删除由next()方法返回的元素
remove()方法可有可无,但如果提供了remove()方法,要注意多线程环境下的使用
我们用java.util.Iterator来重新设计上面的代码:
由于ArrayList类有一个iterator方法,所以只需要为午餐店的数组集合创建一个迭代器即可:
/**
* @author 雫
* @date 2021/3/9 - 15:02
* @function 菜单接口
*/
public interface Menu {
Iterator createIterator();
}
/**
* @author 雫
* @date 2021/3/9 - 14:56
* @function 午餐店菜单迭代器
*/
public class BMenuIterator implements Iterator {
private MenuItem[] menuItems;
private int index;
public BMenuIterator(MenuItem[] menuItems) {
this.menuItems = menuItems;
this.index = 0;
}
@Override
public boolean hasNext() {
if(index >= menuItems.length || menuItems[index] == null) {
return false;
} else {
return true;
}
}
@Override
public Object next() {
MenuItem menuItem = menuItems[index];
index++;
return menuItem;
}
}
/**
* @author 雫
* @date 2021/3/9 - 14:58
* @function
*/
public class BMenu implements Menu {
private static final int MAX_ITEMS = 3;
private int numberOfItems = 0;
private MenuItem[] menuItems;
public BMenu() {
menuItems = new MenuItem[MAX_ITEMS];
addItem("soup", "good soup", true, 20);
addItem("chicken", "nice chicken", false, 40);
addItem("juice", "good juice", true, 15);
}
public void addItem(String name, String description, boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
if(this.numberOfItems >= MAX_ITEMS) {
System.out.println("菜单已满");
} else {
menuItems[numberOfItems] = menuItem;
numberOfItems = numberOfItems + 1;
}
}
@Override
public Iterator createIterator() {
return new BMenuIterator(this.menuItems);
}
}
经过重新设计后,Waiter类可以使用各种集合的迭代器,从而完成对集合的遍历操作,但Waite并不知道集合的具体实现,并与各种菜单类完成了解耦
1.5 定义迭代器模式
迭代器模式:
提供一种方法顺序访问一个集合中的各个元素,且不暴露其内部的实现
对于一个拥有集合的类,我们应该为这个集合设计专用的迭代器,来负责该集合的遍历工作,减轻拥有集合的类的工作量,并同时为该类增加一个获取迭代器的方法
关于迭代器模式,最重要的就是迭代器接口:
/**
* @author 雫
* @date 2021/3/9 - 13:09
* @function 迭代器接口
*/
public interface Iterator {
boolean hasNext();
Object next();
}
hasNext()将用来判断集合中是否还有下一个元素
next()将用来取得这个集合中的下一个元素
一旦有了这个Iterator接口,就可以为各种集合实现迭代器,如数组,列表,散列表等,之后就可以从具体的迭代器中遍历元素,从而屏蔽了集合的具体实现,并且能够写出“多态的代码”
1.6 单一责任原则
设计原则
一个类应该只有一个引起变化的原因
当我们允许一个类不但要完成自己的任务时(管理某种集合),还同时要担负别的责任(遍历集合)时,我们就给了这个类两个变化的原因
为什么是两个?不是只有一个集合吗?
因为当这个集合改变时,这个类就需要改变,当遍历的方式改变时,这个类也需要改变,容易改变的必然不是坚固的
如果一个类有两个或多个职责,那么这会使得该类改变的变化率上升,这个类就变得脆弱,不易维护,应该尽量让每个类只有一种职责,将不同种类的功能分离
内聚:用来衡量一个类或模块的紧密程度
当一个模块或类被设计成只支持一组相关的功能时,称它高内聚,当被设计成支持一组不相关的功能时,称它低内聚
遵守 单一责任原则 的类/模块,更为“高内聚”且更易维护,我们需要高内聚,低耦合的代码
1.7 合并咖啡厅
现在我们的餐厅继续合并咖啡厅,咖啡厅也有它的菜单,菜单项仍然是MenuItem,来看看合并前的咖啡厅菜单:
/**
* @author 雫
* @date 2021/3/10 - 11:35
* @function 咖啡厅菜单
*/
public class CMenu {
private Hashtable<String, MenuItem> menuItems;
public CMenu() {
this.menuItems = new Hashtable();
addItem("coffee", "good coffee", true, 30);
addItem("cake", "nice cake", true, 20);
addItem("hotDog", "good hotDog", false, 15);
}
public void addItem(String name, String description, boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
menuItems.put(menuItem.getName(), menuItem);
}
public Hashtable<String, MenuItem> getItems() {
return this.menuItems;
}
}
现在我们修改咖啡厅的菜单,让它合并到先前的菜单且让招待员能够通过迭代器来遍历,为此我们需要创建一个能返回Hashtable迭代器的方法:
/**
* @author 雫
* @date 2021/3/10 - 11:35
* @function 咖啡厅菜单
*/
public class CMenu implements Menu {
private Hashtable<String, MenuItem> menuItems;
public CMenu() {
this.menuItems = new Hashtable();
addItem("coffee", "good coffee", true, 30);
addItem("cake", "nice cake", true, 20);
addItem("hotDog", "good hotDog", false, 15);
}
public void addItem(String name, String description, boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
menuItems.put(menuItem.getName(), menuItem);
}
@Override
public Iterator createIterator() {
//这种方式可以直接获得Hashtable的迭代器
return menuItems.values().iterator();
}
}
更改好咖啡厅的菜单后,我们将其加入到招待员类中:
/**
* @author 雫
* @date 2021/3/9 - 15:04
* @function 招待员
*/
public class Waiter {
private Menu aMenu;
private Menu bMenu;
private Menu cMenu;
public Waiter(Menu aMenu, Menu bMenu, Menu cMenu) {
this.aMenu = aMenu;
this.bMenu = bMenu;
this.cMenu = cMenu;
}
public void printAll() {
Iterator aIterator = this.aMenu.createIterator();
Iterator bIterator = this.bMenu.createIterator();
Iterator cIterator = this.cMenu.createIterator();
printMenu(aIterator);
printMenu(bIterator);
printMenu(cIterator);
}
public void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
System.out.println(menuItem.getName() + ", " + menuItem.getDescription()
+ ", " + menuItem.isVegetarian() + ", " + menuItem.getPrice());
}
}
}
通过为集合创建迭代器的方式来统一遍历它们,让代码符合单一职责原则,且让遍历集合的类完成了解耦
1.8 迭代器与集合
所有的集合,如ArrayList,Vector,LinkedList,Stack等,这些类都实现了java.util.Collection这个接口,这个接口包含了很多有用的方法,可以操作一群对象
Collection接口中有add(),addAll(),clear(),contains(),equals(),isEmpty(),remove(),size(),iterator()等方法,这些方法在各种具体集合中被重写,以供我们使用,利用iterator方法就可以直接取得该集合的迭代器
Collection和Iterator的好处在于,每个Collection都知道如何创建自己的Iterator,只要调用ArrayList上的iterator(),就可以返回一个具体的Iterator
1.9 优化招待员
我们对比一下招待员在增加遍历咖啡厅菜单功能前后的代码:
/**
* @author 雫
* @date 2021/3/9 - 12:21
* @function 使用迭代器的招待员
* 遍历早餐店和午餐店菜单集合
*/
public class Waiter {
private AMenu aMenu;
private BMenu bMenu;
public Waiter(AMenu aMenu, BMenu bMenu) {
this.aMenu = aMenu;
this.bMenu = bMenu;
}
public void printAll() {
Iterator aIterator = this.aMenu.createIterator();
Iterator bIterator = this.bMenu.createIterator();
printMenu(aIterator);
printMenu(bIterator);
}
public void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
System.out.println(menuItem.getName() + ", " + menuItem.getDescription()
+ ", " + menuItem.isVegetarian() + ", " + menuItem.getPrice());
}
}
}
/**
* @author 雫
* @date 2021/3/9 - 15:04
* @function 招待员
* 遍历早餐店,午餐店,咖啡厅菜单集合
*/
public class Waiter {
private Menu aMenu;
private Menu bMenu;
private Menu cMenu;
public Waiter(Menu aMenu, Menu bMenu, Menu cMenu) {
this.aMenu = aMenu;
this.bMenu = bMenu;
this.cMenu = cMenu;
}
public void printAll() {
Iterator aIterator = this.aMenu.createIterator();
Iterator bIterator = this.bMenu.createIterator();
Iterator cIterator = this.cMenu.createIterator();
printMenu(aIterator);
printMenu(bIterator);
printMenu(cIterator);
}
public void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
System.out.println(menuItem.getName() + ", " + menuItem.getDescription()
+ ", " + menuItem.isVegetarian() + ", " + menuItem.getPrice());
}
}
}
差别很明显,当我们需要遍历新的菜单时,就需要向招待员中增加新的成员,并且更改构造方法,这又违反了开闭原则,每当我们需要增加/删除一种菜单时,就必须修改源码,我们需要将菜单封装起来,一起管理它们
为了统一管理这些菜单,可以将所有的菜单存入ArrayList中,然后遍历这个ArrayList中,依次取出它们的迭代器即可:
/**
* @author 雫
* @date 2021/3/9 - 15:04
* @function 招待员
* 遍历早餐店,午餐店,咖啡厅菜单集合
*/
public class Waiter {
private ArrayList<Menu> menus;
public Waiter(ArrayList<Menu> menus) {
this.menus = menus;
}
public void printAll() {
Iterator menuIterator = this.menus.iterator();
while(menuIterator.hasNext()) {
Menu menu = (Menu) menuIterator.next();
printMenu(menu.createIterator());
}
}
public void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
System.out.println(menuItem.getName() + ", " + menuItem.getDescription()
+ ", " + menuItem.isVegetarian() + ", " + menuItem.getPrice());
}
}
}
这样使得代码符合了开闭原则,更易维护和扩展
1.10 新的问题…
现在无论再合并多少家店,都可以将其菜单加入到招待员存储菜单的ArrayList中,获取其迭代器进行遍历,但是如果原先的菜单发生了变化呢?
如现在午餐店想要加上一个甜点菜单,这个甜点菜单从属于午餐店的菜单,我们现在的代码无法将该甜点菜单加入到招待员管理的菜单中…
我们需要重构代码,以满足更多的需求…
2 组合模式
2.1 定义组合模式
为了增加子菜单,以及未来可能出现的子菜单的子菜单等情况,我们需要某种树形结构,可以容纳菜单,子菜单和菜单项,我们需要在每个菜单及其子菜单之间游走,以遍历任何存在于树形结构中的菜单
组合模式:
允许将对象组合成树形结构来表现“整体/部分”的层次结构,组合能让客户以一致的方式来处理个别对象以及组合对象
即我们将菜单项和菜单全部当作“组件”,菜单项是叶子没有组件,菜单是节点,可以有组件,这样构成一个树形结构,无论是菜单项还是菜单,都是组件,用户可以通过控制组件来控制树形结构中的所有元素
2.2 利用组合模式设计菜单
所有组件的超类:
/**
* @author 雫
* @date 2021/3/10 - 12:49
* @function 菜单和菜单项的抽象超类
*/
public abstract class MenuComponent {
public void add(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public void remove(MenuComponent menuComponent) {
throw new UnsupportedOperationException();
}
public MenuComponent getChild(int i) {
throw new UnsupportedOperationException();
}
public String getName() {
throw new UnsupportedOperationException();
}
public String getDescription() {
throw new UnsupportedOperationException();
}
public boolean isVegetarian() {
throw new UnsupportedOperationException();
}
public double getPrice() {
throw new UnsupportedOperationException();
}
public void print() {
throw new UnsupportedOperationException();
}
}
菜单项(叶子):
/**
* @author 雫
* @date 2021/3/10 - 12:56
* @function 菜单项
*/
public class MenuItem extends MenuComponent{
private String name;
private String description;
private boolean vegetarian;
private double price;
public MenuItem(String name, String description, boolean vegetarian, double price) {
this.name = name;
this.description = description;
this.vegetarian = vegetarian;
this.price = price;
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
@Override
public boolean isVegetarian() {
return vegetarian;
}
@Override
public double getPrice() {
return price;
}
@Override
public void print() {
System.out.println(getName());
System.out.println(getDescription());
if(isVegetarian()) {
System.out.println("Y");
} else {
System.out.println("N");
}
System.out.println(getPrice());
}
}
菜单(节点):
/**
* @author 雫
* @date 2021/3/10 - 13:04
* @function 菜单
*/
public class Menu extends MenuComponent {
private ArrayList<MenuComponent> menuComponents;
private String name;
private String description;
public Menu(String name, String description) {
this.name = name;
this.description = description;
}
@Override
public void add(MenuComponent menuComponent) {
menuComponents.add(menuComponent);
}
@Override
public void remove(MenuComponent menuComponent) {
menuComponents.remove(menuComponent);
}
@Override
public MenuComponent getChild(int i) {
return menuComponents.get(i);
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return description;
}
@Override
public void print() {
System.out.println(getName());
System.out.println(getDescription());
System.out.println("-------");
Iterator iterator = menuComponents.iterator();
while (iterator.hasNext()) {
MenuComponent menuComponent = (MenuComponent) iterator.next();
menuComponent.print();
}
}
}
招待员:
/**
* @author 雫
* @date 2021/3/10 - 13:21
* @function 招待员
*/
public class Waiter {
private MenuComponent allMenus;
public Waiter(MenuComponent allMenus) {
this.allMenus = allMenus;
}
public void printMenu() {
allMenus.print();
}
}
测试:
/**
* @author 雫
* @date 2021/3/10 - 12:59
* @function
*/
public class Test {
public static void main(String[] args) {
MenuComponent AMenu = new Menu("早餐店菜单", "优质早餐供应");
MenuComponent BMenu = new Menu("午餐店菜单", "放心午餐供应");
MenuComponent B1Menu = new Menu("午餐甜点菜单", "午餐店甜点精选");
MenuComponent CMenu = new Menu("咖啡厅菜单", "美味咖啡供应");
MenuComponent allMenus = new Menu("所有菜单", "所有菜单");
allMenus.add(AMenu);
allMenus.add(BMenu);
allMenus.add(CMenu);
AMenu.add(new MenuItem("milk", "good milk", true, 10));
BMenu.add(new MenuItem("burger", "good burger", false, 25));
BMenu.add(B1Menu);
B1Menu.add(new MenuItem("hotDog", "good hotDog", false, 17));
CMenu.add(new MenuItem("coffee", "good coffee", true, 20));
Waiter waiter = new Waiter(allMenus);
waiter.printMenu();
}
}
2.3 迭代器模式&组合模式小结
1,迭代器允许访问某个使用集合的类中集合的元素,且不会暴露该集合的内部结构
2,迭代器提供了一个通用的接口,迭代器将遍历集合的工作封装到了一个对象里
3,应该努力让一个类只有一个责任
4,组合模式提供一个结构,可以包含个别对象和组合对象
5,组合模式允许客户对个别对象和组合对象一视同仁,组合模式中的元素称为组件,组件可以是节点,也可以是叶子