迭代器模式:提供一种方法顺序访问遍历一个聚合(集合)对象中的各个元素,而无需暴露其(集合)内部的实现。
组合模式: 允许将对象组成树形结构来表现“整体/部分”的层次结构,该树形结构可同时包容个别对象和组合对象。组合让客户以一致的方式处理个别对象和组合对象。组合结构内的任意对象称为组件,组件可以是组合,也可以是叶节点(无法再分)。
下面以一个实例说明:
1. 主函数
public class MenuTestDrive {
/**
* @param args
* 组合模式:允许你将对象组合成树形结构来表现“整体/部分”层次结构,树形结构包含了组合以及个别对象。
* 组合能够让客户以一致的方式处理个别对象以及对象组合。迭代器模式是解决方案中的一部分。
* 组合包含组件,组件有两种:组合与叶节点元素。
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
MenuComponent pancakeHouseMenu = new Menu("PANCAKE HOUSE MENU","Breakfast");
MenuComponent dinerMenu = new Menu("DINER MENU","Lunch");
MenuComponent cafeMeun = new Menu("CAFE MENU","Dinner");
MenuComponent dessertMenu = new Menu("DESSERT MENU","Dessert of course!");
MenuComponent allMenus = new Menu("ALL MENUS","All menus combined");
System.out.println("------------------MenuTestDrive main() add differents MenuComponent to allMenus start----------------------");
try{
allMenus.add(pancakeHouseMenu);
allMenus.add(dinerMenu);
allMenus.add(cafeMeun);
dinerMenu.add(new MenuItem("Pasta",
"Spaghetti with Marinara Sauce, and a slice of sourdough bread",
true,
3.89));
dinerMenu.add(dessertMenu);
dessertMenu.add(new MenuItem("Apple Pie",
"Apple Pie with a flakey crust, topped with vanilla ice cream",
true,
1.59));
} catch (Exception e){
e.printStackTrace();
}
System.out.println("------------------MenuTestDrive main() add differents MenuComponent to allMenus end -----------------------");
Waitress waitress = new Waitress(allMenus);
System.out.println("------------------case 1: Waitress not care of how to visit , only use MenuComponent to call interface-----");
waitress.printMenu();
System.out.println("------------------case 2: Waitress use Composite-Iterator mode to filter all 蔬菜vegetarians----------------");
waitress.printVegetarianMenu();
}
}
2.
抽象组件 MenuComponent.java
import java.util.Iterator;
public abstract class MenuComponent {
public void add(MenuComponent menuComponent)
throws UnsupportOperationException {
throw new UnsupportOperationException();
}
public void remove(MenuComponent menuComponent)
throws UnsupportOperationException {
throw new UnsupportOperationException();
}
public MenuComponent getChild(int i) throws UnsupportOperationException {
throw new UnsupportOperationException();
}
public String getName() throws UnsupportOperationException {
throw new UnsupportOperationException();
}
public String getDescription() throws UnsupportOperationException {
throw new UnsupportOperationException();
}
public double getPrice() throws UnsupportOperationException {
throw new UnsupportOperationException();
}
public boolean isVegetarian() throws UnsupportOperationException {
throw new UnsupportOperationException();
}
public void print() throws UnsupportOperationException {
throw new UnsupportOperationException();
}
abstract Iterator createIterator();
}
3. 抽象组件的子类:叶节点MenuItem 和组合Menu
3.1 叶节点组件MenuItem.java
import java.util.Iterator;
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() throws UnsupportOperationException {
// TODO Auto-generated method stub
return name;
}
public String getDescription() throws UnsupportOperationException {
// TODO Auto-generated method stub
return description;
}
public double getPrice() throws UnsupportOperationException {
// TODO Auto-generated method stub
return price;
}
public boolean isVegetarian() throws UnsupportOperationException {
// TODO Auto-generated method stub
return vegetarian;
}
public void print() throws UnsupportOperationException {
// TODO Auto-generated method stub
System.out.print(" " + getName());
if (isVegetarian()) {
System.out.print(" (V) ");
}
System.out.print(" , " + getPrice());
System.out.println(" --" + getDescription());
}
Iterator createIterator() {
// TODO Auto-generated method stub
return new NullIterator();
}
}
3.2 组合组件Menu.java
import java.util.ArrayList;
import java.util.Iterator;
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)
throws UnsupportOperationException {
// TODO Auto-generated method stub
menuComponents.add(menuComponent);
}
public void remove(MenuComponent menuComponent)
throws UnsupportOperationException {
// TODO Auto-generated method stub
menuComponents.remove(menuComponent);
}
public MenuComponent getChild(int i) throws UnsupportOperationException {
// TODO Auto-generated method stub
return (MenuComponent) menuComponents.get(i);
}
public String getName() throws UnsupportOperationException {
// TODO Auto-generated method stub
return name;
}
public String getDescription() throws UnsupportOperationException {
// TODO Auto-generated method stub
return description;
}
public void print() throws UnsupportOperationException {
// TODO Auto-generated method stub
System.out.print("\n" + getName());
System.out.println(" ," + getDescription());
System.out.println(" ----------------");
// 如果我们想要女招待可以使用迭代器变流器整个组合,就不需要在此处使用迭代器遍历,要交给女招待
Iterator it = menuComponents.iterator();
while (it.hasNext()) {
MenuComponent menuCompent = (MenuComponent) it.next();
menuCompent.print();
}
}
// 为了女招待使用迭代器遍历组合,创建该接口
Iterator createIterator() {
// TODO Auto-generated method stub
return new CompositeIterator(menuComponents.iterator());
}
}
4. 实现Iterator迭代器的子类NullIterator.java和CompositeIterator.java
4.1 叶子节点使用createIterator创建NullIterator 迭代器
import java.util.Iterator;
public class NullIterator implements Iterator {
public boolean hasNext() {
// TODO Auto-generated method stub
return false;
}
public Object next() {
// TODO Auto-generated method stub
return null;
}
public void remove() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
}
}
4.2 组合组件使用createIterator创建CompositeIterator 迭代器
该迭代器可遍历组合组件内的所有组件(叶子节点组件和组合组件,子组合组件....)
import java.util.Iterator;
import java.util.Stack;
import java.util.function.Consumer;
// 这是我们创建的便于女招待使用迭代器遍历组合的“组合迭代器”类
// 它的工作是遍历组件内的菜单项,并确保所有的子菜单(以及子子菜单....)都被包括进来
public class CompositeIterator implements Iterator {
Stack stack = new Stack();
// iterator参数是 Menu对象(组合)中的成员ArrayList对象取得的迭代器
public CompositeIterator(Iterator iterator) {
stack.push(iterator);
}
public boolean hasNext() {
// TODO Auto-generated method stub
if (stack.isEmpty()) {
return false;
} else {
Iterator iterator = (Iterator) stack.peek(); // 取出来这个迭代器偷看一下
if (iterator.hasNext()) {
return true;
} else {
stack.pop(); // 将遍历完的迭代器对象弹出堆栈
return hasNext();
}
}
}
public Object next() {
// TODO Auto-generated method stub
if (hasNext()) {
Iterator iterator = (Iterator) stack.peek(); // 取出堆栈存放的迭代器偷看一下
MenuComponent component = (MenuComponent) iterator.next();// 取出该位置对象,并将位置移动到下一个
if (component instanceof Menu) {
stack.push(component.createIterator()); // 如果是子菜单(组合类型),把将要遍历的下一个迭代器对象放入到堆栈,为了下一步的遍历
}
return component;
}
return null;
}
public void remove() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
}
}
5. 自定义异常类UnsupportOperationException
public class UnsupportOperationException extends Exception {
private static final long serialVersionUID = 1L;
UnsupportOperationException() {
}
}
6. 女招待对象Waitress,她有两种需求:不关注一个个去遍历,调用组合组件的接口一次完成;关注如何使用迭代器访问,并筛选出叶子节点做相应operation
import java.util.Iterator;
public class Waitress {
MenuComponent allMenus;
public Waitress(MenuComponent allMenus) {
this.allMenus = allMenus;
}
// 这个接口是女招待调用打印接口,实际是在组合内部打印方法调用迭代器的,女招待不能随意取出任何
public void printMenu() {
try {
allMenus.print();
} catch (UnsupportOperationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 这个接口是用让女招待使用迭代器去遍历组合的,可以随意取出对象
public void printVegetarianMenu() {
Iterator iterator = allMenus.createIterator();
System.out.println("\n VEGETARIAN MENU\n----");
while (iterator.hasNext()) {
MenuComponent menuCompent = (MenuComponent) iterator.next();
try {
if (menuCompent.isVegetarian()) {
menuCompent.print();
}
} catch (UnsupportOperationException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
}
}
}
}
7. 类结构层次:
Menu 和 MenuItem均继承 MenuComponent组件抽象类。
CompositeIterator和NullIterator均实现java内置接口 Iterator。
组合模式的树结构:
Menu
-- -- --
-- --- ----
MenuItem MenuItem Menu
--
--
MenuItem
可以无限扩张。
图片1: 结构类图
11111
图片2:调用图
2222
运行后结果:
------------------MenuTestDrive main() add differents MenuComponent to allMenus start----------------------
------------------MenuTestDrive main() add differents MenuComponent to allMenus end -----------------------
------------------case 1: Waitress not care of how to visit , only use MenuComponent to call interface-----
ALL MENUS ,All menus combined
----------------
PANCAKE HOUSE MENU ,Breakfast
----------------
DINER MENU ,Lunch
----------------
Pasta (V) , 3.89 --Spaghetti with Marinara Sauce, and a slice of sourdough bread
DESSERT MENU ,Dessert of course!
----------------
Apple Pie (V) , 1.59 --Apple Pie with a flakey crust, topped with vanilla ice cream
CAFE MENU ,Dinner
----------------
------------------case 2: Waitress use Composite-Iterator mode to filter all 蔬菜vegetarians----------------
VEGETARIAN MENU
----
Pasta (V) , 3.89 --Spaghetti with Marinara Sauce, and a slice of sourdough bread
Apple Pie (V) , 1.59 --Apple Pie with a flakey crust, topped with vanilla ice cream
Apple Pie (V) , 1.59 --Apple Pie with a flakey crust, topped with vanilla ice cream