迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
迭代器模式把在元素之间游走的责任交给迭代器,而不是聚合对象。
需求实例:遍历两份不同的菜单,其中早餐菜单使用数组保存菜单项,而午餐使用List保存菜单项。
1、使用java.util.Iterator接口
public interface Iterator<E> {
boolean hasNext();
E next();
default void remove() {
throw new UnsupportedOperationException("remove");
}
}
2、因为List有一个返回迭代器的iterator()方法,不需要自己实现迭代器。但是数组不支持iterator()方法。需要实现一个迭代器。
import java.util.Iterator;
public class DinnerMenuIterator implements Iterator {
MenuItem[] list;
int position=0;
public DinnerMenuIterator(MenuItem[] list){
this.list=list;
}
public Object next() {
MenuItem menuItem=list[position];
position+=1;
return menuItem;
}
public boolean hasNext() {
if(position>=list.length||list[position]==null){
return false;
}else {
return true;
}
}
//删除数组中的元素,后面的元素往前移动一个位置
public void remove() {
if(position<0){
throw new IllegalStateException("");
}
if(list[position-1]!=null){
for(int i=position-1;i<list.length-1;i++){
list[i]=list[i+1];
}
list[list.length-1]=null;
}
}
}
3、菜单接口
public interface Menu {
//主要产生迭代器
public Iterator createIterator();
}
4、两份不同的菜单
public class DinnerMenu implements Menu {
MenuItem[] list;
public Iterator createIterator() {
//产生自己的迭代器
return new DinnerMenuIterator(list);
}
}
public class PankMenu implements Menu{
ArrayList menuItems;
//直接调用iterator()方法
public Iterator createIterator() {
return menuItems.iterator();
}
}
5、遍历菜单项
public class Waitress {
Menu dinnerMenu;
Menu pankMenu;
//针对接口,而不针对实现
public Waitress(Menu dinnerMenu,Menu pankMenu){
this.dinnerMenu=dinnerMenu;
this.pankMenu=pankMenu;
}
public void printMenu(){
//获得迭代器
Iterator pankIterator=pankMenu.createIterator();
Iterator dinnerIterator=dinnerMenu.createIterator();
printMenu(pankIterator);
printMenu(dinnerIterator);
}
public void printMenu(Iterator iterator){
while(iterator.hasNext()){
MenuItem menuItem=(MenuItem)iterator.next();
}
}
}
餐厅不仅要支持多个菜单,甚至还要支持菜单中的菜单(比如,餐后甜点的子菜单)。可能需要遍历甜点菜单,或者遍历整个餐厅菜单。
组合模式
组合模式允许将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合,也就是在大多数情况下,可以忽略对象组合和个别对象之间的差别。
这个模式能够创建一个树形结构,在同一个结构中处理嵌套菜单和菜单项组。通过将菜单和项放在相同的结构中,创建一个”整体/部分”层次结构,即由菜单和菜单项组成的对象树。
有一个树形结构的菜单、子菜单和可能带有菜单项的子菜单,那么任何一个菜单都是一种组合。因为它既可以包含其他菜单,也可以包含菜单项。
(带子元素的元素称为节点,没有子元素的元素称为叶节点)
组合包含组件。组件有两种:组合与叶节点元素。当使用这种方式组织数据,最终会得到由上而下的树形结构,根部是一个组合,而组合的分支逐渐往下延伸,直到叶节点为止。
创建一个组件接口来作为菜单和菜单项的共同接口,能够用统一的方法处理菜单和菜单项。(菜单由不同的菜单项和其他菜单组成)
一、共同接口:为菜单项和菜单提供共同的接口
所有组件都必须实现MenuComponent 接口,叶节点和组合节点的方法并不一致,最好抛出运行异常。
public abstract class MenuComponent {
//新增、删除、取得子菜单
public void add(MenuComponent menuComponent){
//提供默认实现,因为菜单项与菜单的方法有些不一样
throw new UnsupportedOperationException();
}
public void remove(MenuComponent menuComponent){
throw new UnsupportedOperationException();
}
public MenuComponent getChild(){
throw new UnsupportedOperationException();
}
//获取菜单项的信息
public String getName(){
throw new UnsupportedOperationException();
}
public String getDesc(){
throw new UnsupportedOperationException();
}
public void print(){
throw new UnsupportedOperationException();
}
}
二、实现菜单项
public class MenuItem extends MenuComponent {
String name;
String desc;
public MenuItem(String name, String desc) {
this.name = name;
this.desc = desc;
}
//覆盖继承的方法
public String getName(){
return name;
}
public String getDesc(){
return desc;
}
//打印出菜单项信息
public void print(){
System.out.println("name="+getName()+"desc="+getDesc());
}
}
三、实现组合菜单
该组合既包括菜单项也包括其他菜单。
public class Menu extends MenuComponent {
//可以包含任意个菜单项和子菜单
ArrayList list=new ArrayList();
String name;
String desc;
public Menu(String name, String desc) {
this.name = name;
this.desc = desc;
}
public void add(MenuComponent menuComponent){
list.add(menuComponent);
}
public void remove(MenuComponent menuComponent){
list.remove(menuComponent);
}
public String getName(){
return name;
}
public void print(){
//打印菜单包括的子元素:菜单项和其他菜单
Iterator iterator=list.iterator();
while(iterator.hasNext()){
MenuComponent menuComponent=(MenuComponent)iterator.next();
//遇到其他菜单,出现不断递归
menuComponent.print();
}
}
}
四、测试
public static void main(String[] args) {
//创建菜单
MenuComponent pankMenu=new Menu("pank house","good ");
MenuComponent dinnerMenu=new Menu("dinner house","bad");
//创建一个顶层菜单
MenuComponent allMenu=new Menu("all menu","all menu combine");
//给顶层菜单添加子菜单
allMenu.add(pankMenu);
allMenu.add(dinnerMenu);
//子菜单添加菜单项
pankMenu.add(new MenuItem("pasta","nice"));
//输出所有菜单
allMenu.print();
}