先说一下题外话,这个模式是我学的最累的模式,代码纠结无比,而且似乎又不经常用,但是我还是硬着头皮把这个模式给看完了。废话不多说,开始干活.......
意图:允许你将对象组成属性结构来表现“整体/部分”的层次结构,组合能让客户以一直的方式处理个别的对象和对象组合。
结构:
首先是组合包含组件,组件有两种:组合与叶节点元素。
接着我们继续看例子:
在原有的对象餐厅我们添加了晚餐-咖啡餐厅,而咖啡餐厅却有甜点子菜单,这样原有的迭代器模式就不能顺利解决问题了,我们要使用组合与迭代模式的联合:
首先我们来看组合模式该如何进行:
在看具体的代码,从接口MenuComponent开始:
import java.util.*;
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 abstract Iterator createIterator();
public void print() {
throw new UnsupportedOperationException();
}
}
因为菜单是一个组合,我们来看菜单具体的实现代码:
import java.util.Iterator;
import java.util.ArrayList;
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();
}
}
}
其中特别注意的是print函数,由于menu菜单是组合我们只能调用菜单组件接口的print方法.
这个我们已经成功在内部使用迭代器,遍历整个目标,但是我们还是需要实现一个功能,就是女Waitress像调用这个迭代器那该如何操作,这时候我们就需要创建一个新的外部迭代器:首先我们要实现两个外部迭代器,一个是NullIteractor另一个是CompositeIterator。
NullIterator 代码:
public class NullIterator implements Iterator {
public Object next() {
return null;
}
public boolean hasNext() {
return false;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
CompositeIterator 代码为:
import java.util.*;
public class CompositeIterator implements Iterator {
Stack stack = new Stack();
public CompositeIterator(Iterator iterator) {
stack.push(iterator);
}
public Object next() {
if (hasNext()) {
Iterator iterator = (Iterator) stack.peek();
MenuComponent component = (MenuComponent) iterator.next();
if (component instanceof Menu) {
stack.push(component.createIterator());
}
return component;
} else {
return null;
}
}
public boolean hasNext() {
if (stack.empty()) {
return false;
} else {
Iterator iterator = (Iterator) stack.peek();
if (!iterator.hasNext()) {
stack.pop();
return hasNext();
} else {
return true;
}
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
为什么要实现两个呢?一个是为“叶子”准备的,另一个是为“节点”准备的。
首先在menuItem实现createIteractor()
public Iterator createIterator() {
return new NullIterator();
}
然后是menu实现createIteractor()
public Iterator createIterator() {
return new CompositeIterator(menuComponents.iterator());
}
最后我们来看女Waitress如何运用这个迭代器的:
public void printVegetarianMenu() {
Iterator iterator = allMenus.createIterator();
System.out.println("\nVEGETARIAN MENU\n----");
while (iterator.hasNext()) {
MenuComponent menuComponent =
(MenuComponent)iterator.next();
try {
if (menuComponent.isVegetarian()) {
menuComponent.print();
}
} catch (UnsupportedOperationException e) {}
}
}