想象一个场景,有两个对象(称为聚合对象),一个对象的存储方式是ArrayList,另一个对象存储方式是数组。你是客户端,想遍历这两种数据结构。方案一:分别针对这两种写遍历方法,但是这样代码会变的相当冗余。而方案二:就是迭代器,使用统一的接口来处理不同的集合,并且隐藏了具体的存储方式。就想一个小区里住了很多户人家,要找他们,从前你要到他们家,但是后来小区请了门卫,有门卫来帮你联系。
另外做为迭代器,首先你要获取数据(构造方法),你至少要有最小的执行单位,一个是next()来获取下一个数据,那随之而来就需要判断下一个是否存在,需要hasNext()方法,再加remove()方法。并且聚合对象要实现迭代器接口,这样客户端就可以针对接口编程,还要需要返回一个迭代器方法,把聚合对象传入进去。
看下定义,迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
方法就是next()和hasNext()方法。
这里涉及一个原则,一个类应该只有一个引起变化的原因。
代码
public interface Menu {
public Iterator createIterator();
}
public class DinerMenu implements Menu{
static final int MAX_ITEMS = 6;
int numberOfItems = 0;
MenuItem[] menuItems;
public DinerMenu(){
menuItems = new MenuItem[MAX_ITEMS];
addItem("Vegetarian BLT","Bacon with lettuce",true,2.99);
addItem("Soup","Soup of the day",false,2.99);
}
public void addItem(String name,String description,
boolean vegetarian,double price){
MenuItem menuItem = new MenuItem(name,description,vegetarian,price);
if(numberOfItems >= MAX_ITEMS){
System.err.println("sorry");
}else{
menuItems[numberOfItems] = menuItem;
numberOfItems++;
}
}
public Iterator createIterator(){
return new DinerMenuIterator(menuItems);
}
}
public class PancakeHouseMenu implements Menu{
ArrayList menuItems;
public PancakeHouseMenu(){
menuItems = new ArrayList();
addItem("Pancake BLT","Pancakes with egg",true,3.99);
addItem("Blueberry Pancakes","Blueberry",false,2.59);
}
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 menuItems.iterator();
}
}
public class MenuItem {
String name;
String description;
boolean vegetarian;
double price;
public MenuItem(String name, String description, boolean vegetarian,
double price) {
super();
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;
}
}
public class Waitress {
Menu pancakeHouseMenu;
Menu DinerMenu;
public Waitress(Menu pancake,Menu diner){
this.pancakeHouseMenu = pancake;
this.DinerMenu = diner;
}
public void printMenu(){
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = DinerMenu.createIterator();
System.out.println("MENU\n----\nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
}
private void printMenu(Iterator iterator){
while(iterator.hasNext()){
MenuItem menuItem = (MenuItem)iterator.next();
System.out.println(menuItem.getName() + ", ");
System.out.println(menuItem.getPrice() + "--");
System.out.println(menuItem.getDescription());
}
}
}
public class MenuTestDrive {
public static void main(String[] args) {
PancakeHouseMenu pancake = new PancakeHouseMenu();
DinerMenu dinerMenu = new DinerMenu();
Waitress waitress = new Waitress(pancake,dinerMenu);
waitress.printMenu();
}
}
组合模式
想象一下这样一个场景,餐单,里面有时不仅包含餐点,同时也包含其他餐单,而这餐单里又包含了同样的餐单。这是一种树形结构(组合结构),使用这种结构,我们能把相同的操作应用在组合和个别对象中。
概念,组合对象中,有根(最上层的餐单组件),结点(菜单组件),叶子(菜单项)的概念。
看下定义:组合模式:允许你将对象组合成树形结构来表现”整体/部分”层次结构,组合能让客户以一致的方式处理个别对象以及对象组合。
看类图就明白了
通过叶子和结点同实现共同的接口来实现。在高层抽象类定义所需的方法。
这里的难点是怎么遍历菜单组下面所有的元素。
两种方法:
1.通过递归,共同实现同一个方法,不论是叶子还是结点,通过调用自身来遍历所有。
2.通过实现外部迭代器,通过对迭代器进行操作来代替对链表的直接操作。
代码:
public class CompositeIterator implements Iterator{
Stack stack = new Stack();
public CompositeIterator(Iterator iterator){
stack.push(iterator);
}
@Override
public boolean hasNext() {
if(stack.empty()){
return false;
}else{
Iterator iterator = (Iterator)stack.peek();
if(!iterator.hasNext()){
stack.pop();
return hasNext();
}else{
return true;
}
}
}
@Override
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;
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
例子代码
最顶层抽象类
public abstract class MenuComponent {
public void add(MenuComponent Component){
throw new UnsupportedOperationException();
}
public void remove(MenuComponent Component){
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();
}
}
菜单组(结点)
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 Component){
menuComponents.add(Component);
}
public void remove(MenuComponent Component){
menuComponents.remove(Component);
}
public String getName(){
return name;
}
public String getDescription(){
return description;
}
public void print(){
System.out.print("\n" + getName());
System.out.print(", " + 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());
}
}
叶子
public class MenuItem extends MenuComponent{
String name;
String description;
boolean vegetarian;
double price;
public MenuItem(String name, String description, boolean vegetarian,
double price) {
super();
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;
}
public void print(){
System.out.println(" " + getName());
if(isVegetarian()){
System.out.println("(v)");
}
System.out.println(", " + getPrice());
System.out.println(" --" + getDescription());
}
}
客户端
public class Waitress {
MenuComponent allMenus;
public Waitress(MenuComponent allMenus){
this.allMenus = allMenus;
}
public void printMenu(){
allMenus.print();
}
public void printVegetariarianMenu(){
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 (Exception e) {
// TODO: handle exception
}
}
}
}
public class MenuTestDrive {
public static void main(String args[]){
MenuComponent pancakeHouseMenu =
new Menu("PANCAKE House","Breakfast");
MenuComponent dinerMenu =
new Menu("DINER MENU","Lunch");
MenuComponent dessertMenu =
new Menu("DESSERT MENU","DESSERT of course");
MenuComponent allMenus = new Menu("All menus","All menus");
allMenus.add(pancakeHouseMenu);
allMenus.add(dinerMenu);
allMenus.add(dessertMenu);
dinerMenu.add(new MenuItem("Pasta","Spaghetti",true,3.89));
dinerMenu.add(dessertMenu);
dessertMenu.add(new MenuItem("Apple Pie","Apple",true,1.59));
Waitress waitress = new Waitress(allMenus);
waitress.printMenu();
System.out.println("----------------------------------");
waitress.printVegetariarianMenu();
}
}