迭代器和组合模式

什么是迭代器、组合模式

迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露内部的表示。
组合模式:允许你将组合对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合

实现了组合模式的小例子

餐厅里边有供应早餐,午餐和晚餐,每餐供应的餐食又不同,我们要做的就是使用组合模式打印所有菜单
首先有一个所有菜单的基类,所有的菜单都必须继承自该类,里边关于菜单的操作我们都交给具体的菜单类去完成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* 菜单抽象类,所有菜单都必须实现
*/
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 double getPrice(){
throw new UnsupportedOperationException();
}
public boolean isVegetarian(){
throw new UnsupportedOperationException();
}
public void print(){
throw new UnsupportedOperationException();
}
public Iterator createIterator(){
throw new UnsupportedOperationException();
}
}

实现组合菜单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* 菜单
*/
public class Menu extends MenuComponent {
ArrayList menuComponents = new ArrayList();
String name;
String description;
public Menu(String name,String description){
this.name = name;
this.description = description;
}
public void add(MenuComponent menuComponent){
menuComponents.add(menuComponent);
}
public void remove(MenuComponent menuComponent){
menuComponents.remove(menuComponent);
}
public MenuComponent getChild(int i){
return (MenuComponent) menuComponents.get(i);
}
public String getName(){
return name;
}
public String getDescription(){
return description;
}
public void print(){
System.out.print("\n"+getName());
System.out.println(", "+getDescription());
System.out.println("这里是分割线======>");
Iterator iterator = menuComponents.iterator();
while(iterator.hasNext()){
MenuComponent menuComponent = (MenuComponent)iterator.next();
menuComponent.print();
}
}
public Iterator createIterator(){
return new CompositeIterator(menuComponents.iterator());
}
}

实现菜单项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* 菜单项类
*/
public class MenuItem extends MenuComponent {
String name;
String description;
boolean vegetarian;
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 double getPrice(){
return price;
}
public boolean isVegetarian(){
return vegetarian;
}
public void print(){
System.out.print(" "+getName());
if(isVegetarian()){
System.out.print("(v)");
}
System.out.println(", "+getPrice());
System.out.println(" --"+getDescription());
}
public Iterator createIterator(){
return new NullIterator();
}
}

菜单和菜单项类我们都有了,接下来要让服务员把菜单提供给客户看(打印出来)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Waitress {
MenuComponent allMenus;
public Waitress(MenuComponent allMenus){
this.allMenus = allMenus;
}
public void printMenu(){
allMenus.print();
}
public void printVegetarianMenu(){
Iterator iterator = allMenus.createIterator();
System.out.println("\n素食菜单\n-----");
while(iterator.hasNext()){
MenuComponent menuComponent = (MenuComponent)iterator.next();
try {
if(menuComponent.isVegetarian()){
menuComponent.print();
}
}catch (UnsupportedOperationException e){}
}
}
}

做一个测试类测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MenuTestDrive {
public static void main(String[] args){
MenuComponent pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU","供应早餐");
MenuComponent dinnerMenu = new Menu("DINNER MENU","供应午餐");
MenuComponent cafeMenu = new Menu("CAFE MENU","供应晚餐");
MenuComponent dessertMenu = new Menu("DESSERT MENU","餐后甜点");
MenuComponent allMenu = new Menu("ALL MENUS","全部菜单组合");
allMenu.add(pancakeHouseMenu);
allMenu.add(dinnerMenu);
allMenu.add(cafeMenu);
dinnerMenu.add(new MenuItem("Pasta","好吃的意大利面",true,3.89));
dinnerMenu.add(dessertMenu);
dessertMenu.add(new MenuItem("Apple Pie","好吃的苹果饼",true,1.59));
Waitress waitress = new Waitress(allMenu);
waitress.printMenu();
//System.out.println("使用外部迭代器打印素食菜单");
//waitress.printVegetarianMenu();
}
}

打印结果
ALL MENUS, 全部菜单组合
这里是分割线======>

PANCAKE HOUSE MENU, 供应早餐
这里是分割线======>

DINNER MENU, 供应午餐
这里是分割线======>
Pasta(v), 3.89
–好吃的意大利面

DESSERT MENU, 餐后甜点
这里是分割线======>
Apple Pie(v), 1.59
–好吃的苹果饼

CAFE MENU, 供应晚餐
这里是分割线======>

总结

1.迭代器允许访问聚合的元素,而不需要暴露它的内部结构
2.迭代器将遍历聚合的工作封装进一个对象中
3.当使用迭代器的时候,我们依赖聚合提供遍历
4.迭代器提供了一个通用的接口,让我们遍历聚合项,当我们的编码使用聚合的项时,就可以使用多态机制。
5.我们应该努力让一个类只分配一个责任
6.组合模式提供一个结构,可同时包容个别对像和组合对象
7.组合模式允许客户对个别对象以及组合对象一视同仁
8.组合结构内的任意对象称为组件,组件可以是组合,也可以是叶节点
9.在实现组合模式时,有许多设计上的折衷。要根据需要平衡透明性和安全性