趣解设计模式之《小店儿菜单的故事》

〇、小故事

在一座小镇上,有两家特别有名气的小店,一家是远近闻名的早餐店 ,它家的早餐特别好吃,每天早上都能排起长长的队伍;另一家是个蛋糕店,他家是专门从法国请来的蛋糕师傅,蛋糕的香味真是香飘万里。

自从听说这个酱香拿铁 销量非常高之后,这两家店的老板们就觉得强强联合才是能让小店更进一步的关键,所以,两家老板打算合并起来一起做生意。

但是呢,早餐店的菜单是ArrayList维护的,蛋糕店的菜单是数组维护的 。那么对于服务员来说,他报菜单的时候,既要针对ArrayList类型的菜单进行遍历输出菜品,又需要再针对数组进行遍历输出菜品。并且,如果后面合并的小店越来越多,菜单用了其他的数据结构存储怎么办呢? 如果强制所有的饭店都使用统一的集合类型去存储菜单的话,那么对小店来说,所有用到旧菜单的地方都需要代码修改。这样改动太大了呀。

为了解决这个问题,我们统一提供了迭代器接口,每个饭店的菜单都要实现迭代器这个接口。那么这就是今天要给大家介绍的设计模式------迭代器模式

一、模式定义

迭代器模式Iterator Pattern

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

二、模式类图

针对上面两个小店合并后菜单类型不一致导致的遍历问题,我们来看一下如何采用迭代模式来解决。首先,我们要创建菜单接口类Menu ,以及两个饭店的菜单实现类,分别是:ARestaurantMenuBRestaurantMenu 。其次,创建菜单迭代器接口MenuIterator和两个饭店的菜单迭代器实现类,分别是:ARestaurantMenuIteratorBRestaurantMenuIterator 。最后,创建服务员类Waitress 和菜单项类MenuItem。具体类图请见如下所示:

三、代码实现

创建菜单明细项MenuItem.java

java 复制代码
public class MenuItem {
    // 菜名
    private String name;
    // 菜品详细介绍
    private String desc;
    // 是否是素食
    private boolean vegetarian;
    // 菜的价格
    private double price;

    public MenuItem(String name, String desc, boolean vegetarian, double price) {
        this.name = name;
        this.desc = desc;
        this.vegetarian = vegetarian;
        this.price = price;
    }
	/** xxxGet()和xxxSet()方法*/
}

创建小店菜单接口Menu.java

java 复制代码
public interface Menu {
    MenuIterator iterator(); // 获得迭代器
}

创建A饭店菜单实现类ARestaurantMenu.java

java 复制代码
public class ARestaurantMenu implements Menu {
    private ArrayList<MenuItem> menuItems;
    public ARestaurantMenu() {
        menuItems = new ArrayList<>();
        addItem("油条", "油条的描述", true, 0.5);
        addItem("豆浆", "豆浆的描述", true, 1.9);
        addItem("茶叶蛋", "茶叶蛋的描述", true, 1.5);
        addItem("小笼包", "小笼包的描述", true, 2.1);
    }

    private void addItem(String name, String desc, boolean vegetarian, double price) {
        MenuItem menuItem = new MenuItem(name, desc, vegetarian, price);
        menuItems.add(menuItem);
    }

    public ArrayList<MenuItem> getMenuItems() {
        return menuItems;
    }

    @Override
    public MenuIterator iterator() {
        return new ARestaurantMenuIterator(menuItems);
    }
}

创建B饭店菜单实现类BRestaurantMenu.java

java 复制代码
public class BRestaurantMenu implements Menu {
    int nums = 0;
    private static final int MAX_SIZE = 5; // 餐厅老板很有个性,只做5道菜
    private MenuItem[] menuItems;

    public BRestaurantMenu() {
        menuItems = new MenuItem[MAX_SIZE];
        addItem("宫保鸡丁", "宫保鸡丁的描述", true, 0.5);
        addItem("北京烤鸭", "北京烤鸭的描述", true, 1.9);
        addItem("黄焖鸡米饭", "黄焖鸡米饭的描述", true, 1.5);
        addItem("啵啵鱼", "啵啵鱼的描述", true, 2.1);
        addItem("兰州拉面", "兰州拉面的描述", true, 2.1);
    }

    private void addItem(String name, String desc, boolean vegetarian, double price) {
        MenuItem menuItem = new MenuItem(name, desc, vegetarian, price);
        if (nums >= MAX_SIZE) {
            System.out.println("菜单满了!老板不做了!");
            return;
        }
        menuItems[nums++] = menuItem;
    }

    public MenuItem[] getMenuItems() {
        return menuItems;
    }

    @Override
    public MenuIterator iterator() {
        return new BRestaurantMenuIterator(menuItems);
    }
}

创建菜单迭代器接口类MenuIterator.java

java 复制代码
public interface MenuIterator {
    // 容器中是否还有元素
    boolean hasNext();
    // 获得容器中的下一个元素
    MenuItem next();
}

创建A饭店的菜单迭代器实现类ARestaurantMenuIterator.java

java 复制代码
public class ARestaurantMenuIterator implements MenuIterator {
    private ArrayList<MenuItem> menuItems;
    private Iterator<MenuItem> iterator;

    public ARestaurantMenuIterator(ArrayList<MenuItem> menuItems) {
        this.menuItems = menuItems;
        iterator = menuItems.iterator();
    }

    @Override
    public boolean hasNext() {
        return iterator.hasNext();
    }

    @Override
    public MenuItem next() {
        return iterator.next();
    }
}

创建B饭店的菜单迭代器实现类BRestaurantMenuIterator.java

java 复制代码
public class BRestaurantMenuIterator implements MenuIterator {
    private MenuItem[] menuItems;
    private int i = 0;

    public BRestaurantMenuIterator(MenuItem[] menuItems) {
        this.menuItems = menuItems;
    }

    @Override
    public boolean hasNext() {
        return menuItems != null && i < menuItems.length && menuItems[i] != null;
    }

    @Override
    public MenuItem next() {
        return menuItems[i++];
    }
}

创建服务员类Waitress.java

java 复制代码
public class Waitress {
    /** 服务员打印菜单 */
    public void printMenu(Menu... menus) {
        for (Menu menu : menus) {
            print(menu.iterator());
        }
    }

    private void print(MenuIterator iterator) {
        MenuItem menuItem;
        while (iterator.hasNext()) {
            menuItem = iterator.next();
            System.out.println(String.format("name=%s, desc=%s, price=%s", menuItem.getName(), 
                                             menuItem.getDesc(), menuItem.getPrice()));
        }
    }
}

创建测试类IteratorTest.java

java 复制代码
public class IteratorTest {
    public static void main(String[] args) {
        /** 构建A餐馆和B餐馆的菜单 */
        ARestaurantMenu aMenu = new ARestaurantMenu();
        BRestaurantMenu bMenu = new BRestaurantMenu();
        /** 构建女服务员 */
        Waitress waitress = new Waitress();
        /** 将A餐馆和B餐馆的菜单传给服务员,让她报出菜单来 */
        waitress.printMenu(aMenu, bMenu);
    }
}

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享

更多技术干货,欢迎大家关注公众号"爪哇缪斯" ~ \(^o^)/ ~ 「干货分享,每天更新」

相关推荐
【D'accumulation】3 分钟前
令牌主动失效机制范例(利用redis)注释分析
java·spring boot·redis·后端
小叶学C++9 分钟前
【C++】类与对象(下)
java·开发语言·c++
2401_8543910813 分钟前
高效开发:SpringBoot网上租赁系统实现细节
java·spring boot·后端
Cikiss21 分钟前
微服务实战——SpringCache 整合 Redis
java·redis·后端·微服务
wxin_VXbishe22 分钟前
springboot合肥师范学院实习实训管理系统-计算机毕业设计源码31290
java·spring boot·python·spring·servlet·django·php
Cikiss23 分钟前
微服务实战——平台属性
java·数据库·后端·微服务
无敌の星仔32 分钟前
一个月学会Java 第2天 认识类与对象
java·开发语言
OEC小胖胖36 分钟前
Spring Boot + MyBatis 项目中常用注解详解(万字长篇解读)
java·spring boot·后端·spring·mybatis·web
2401_857617621 小时前
SpringBoot校园资料平台:开发与部署指南
java·spring boot·后端
quokka561 小时前
Springboot 整合 logback 日志框架
java·spring boot·logback