迭代器与组合模式

迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

迭代器模式把在元素之间游走的责任交给迭代器,而不是聚合对象。
这里写图片描述

需求实例:遍历两份不同的菜单,其中早餐菜单使用数组保存菜单项,而午餐使用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();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值