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

news2025/7/18 10:48:32

〇、小故事

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

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

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

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

一、模式定义

迭代器模式Iterator Pattern

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

二、模式类图

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

三、代码实现

创建菜单明细项MenuItem.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

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

创建A饭店菜单实现类ARestaurantMenu.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

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

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

创建A饭店的菜单迭代器实现类ARestaurantMenuIterator.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

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

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

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^)/ ~ 「干货分享,每天更新」

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1010408.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp微信小程序《隐私保护协议》弹窗处理流程

背景 《关于小程序隐私保护指引设置的公告》 《小程序隐私协议开发指南》 流程 1.第一步 必须设置且审核通过&#xff01;&#xff01;&#xff01; 2.第二步 uniapp在manifest.json中添加&#xff01;&#xff01;&#xff01; /* 在 2023年9月15号之前&#xff0c;在 ap…

汽车电子智能仓储系统的发展趋势与应用探索

现代汽车制造业中的仓储管理一直面临着多种挑战。仓库中物料的数量种类繁多&#xff0c;寻找物料耗时长、困难大。盘点过程耗费人力多、成本高、速度慢。管理无法达到先进先出的原则&#xff0c;也无法进行精准追溯。此外&#xff0c;多发、少发、错料等问题时有发生。仓库中的…

docker学习:dockerfile和docker-compose

学习如何使用dockerfile 以下内容&#xff0c;部分来自gpt生成&#xff0c;里面的描述可能会出现问题&#xff0c;但代码部分&#xff0c;我都会进行测试。 1. 需求 对于一个docker&#xff0c;例如python&#xff0c;我们需要其在构建成容器时&#xff0c;就有np。有以下两种方…

Linux内核源码分析 (B.x)Linux物理内存的初始化

Linux内核源码分析 (B.x)Linux物理内存的初始化 文章目录 Linux内核源码分析 (B.x)Linux物理内存的初始化一、DDR简介二、内存节点三、内存管理区域ZONE四、 struct zone五、 struct page六、mem_map数组七、伙伴系统简介八、迁移类型九、内存初始化十、总结 一、DDR简介 详细可…

电脑msvcp140.dll丢失问题的三种解决方法分享,快速修复dll问题

在我们的日常生活中&#xff0c;计算机已经成为了我们工作、学习和娱乐的重要工具。然而&#xff0c;在使用计算机的过程中&#xff0c;我们可能会遇到各种问题&#xff0c;其中之一就是 msvcp140.dll 丢失的困扰。本文将详细介绍 msvcp140.dll 丢失的原因、解决方法以及预防措…

可变参数JAVA

public class Main {public static void main(String[] args) {//方法形参的个数是可以变化的//格式&#xff1a;属性类型...名字System.out.println(getSum(1,2,3,4,5,6,7,8));}//通过键值对对象来遍历&#xff1b;public static int getSum(int a,int...args){//可变参数;int…

AirTag是什么?高精度测距定位防丢,UWB厘米级方案应用

随着科技的不断发展&#xff0c;超宽带&#xff08;UWB&#xff09;技术作为一种新兴的无线通信技术&#xff0c;逐渐受到人们的关注和追捧。 UWB技术以其传输速率高、抗干扰性强、带宽极宽、功耗低、安全性高、穿透力强、定位精准等优势&#xff0c;在众多领域具有广泛的应用…

输电线路故障数据集(基于simulink仿真批量生成故障数据,单相接地故障、两相接地故障、两相间短路故障、三相接地故障、三相间短路故障和正常)

分别获取单相接地故障、两相接地故障、两相间短路故障、三相接地故障、三相间短路故障和正常状态下的电流&#xff08;Ia,Ib,Ic&#xff09;大小和电压&#xff08;Ua,Ub和Uc&#xff09;大小。每种故障下获取1300行左右的数据 将故障区分为具体的不同类型&#xff08;一共五种…

JetBrains设置inline hint的背景色、前景色

如题。修改IDE的hint前景色和背景色。 修改后结果&#xff1a;

为什么DasViewer打开之后一直白屏?如图

答&#xff1a;这种情况可以检查一下电脑的集显驱动。 DasViewer是由大势智慧自主研发的免费的实景三维模型浏览器,采用多细节层次模型逐步自适应加载技术,让用户在极低的电脑配置下,也能流畅的加载较大规模实景三维模型,提供方便快捷的数据浏览操作。#DasViewer##实景三维##三…

跟踪源码技巧+阅读源码工具Sourcetrail

基于Eclipse IDE 1、Quick Type Hierarchy 快速查看类继承体系 &#xff08; 快捷键&#xff1a;Ctrl T&#xff09; 查看类很多人可能都知道&#xff0c;可源码阅读的时候更多用来查看方法体系更重要&#xff0c;可以方便快速的定位到方法的实现类。如&#xff1a; 此时如…

Mendelay-文献管理软件使用教程

Mendelay-文献管理软件 注册账号 注册账号 打开官网&#xff0c;注册个人账号 通过邮箱就可以注册账号啦&#xff0c;这是登录后的页面&#xff0c;并下载Mendeley客户端。 安装好客户端&#xff0c;打开软件首先登录以上注册的账号&#xff0c;则可进入客户端首页。

《安富莱嵌入式周报》第322期:自制10KV电子负载,史上最详细的电池系列资料,创意洞洞板任意互联,开源USB分析仪,英特尔雷电5, QNX功能安全免费课程

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版&#xff1a; https://www.bilibili.com/video/BV1M8411q7dw/ 《安富莱嵌入式周报》第322期&#xff1a;自制10K…

nvue文件中@click.stop失效

在nvue文件中在子元素使用click.stop失效&#xff0c;父元素的事件触发了 在uniapp开发中nvue文件是跟vue文件是不一样的&#xff0c;就比如click.stop阻止点击事件继续传播就失效了&#xff0c;这时我们需要在子元素事件中添加条件编译&#xff0c;这样就会解决这个问题 // …

图论第三天|130. 被围绕的区域、417. 太平洋大西洋水流问题、827. 最大人工岛

130. 被围绕的区域 文档讲解 &#xff1a;代码随想录 - 130. 被围绕的区域 状态&#xff1a;开始学习。 思路&#xff1a; 步骤一&#xff1a; 深搜或者广搜将地图周边的 ‘O’ 全部改成 ’A’&#xff0c;如图所示&#xff1a; 步骤二&#xff1a; 再遍历地图&#xff0c;将 …

记录一次使用网云穿实现内网穿透操作

记录一次使用网云穿实现内网穿透操作 摘要 这段时间也很少写博客了,一方面工作表较忙,一方面觉得有些东西在百度上都能找到,甚至比我自己记录的详细,有些笔记也就没打, 这次记录笔记主要是觉得这个 网云穿 很好用,分享给大家. 1 什么是内网穿透? 内网穿透也叫内网映射&#xf…

zookeeper最基础教程

文章目录 一、简介1、工作机制2、特点3、数据结构4、应用场景5、选举机制 二、软件安装1、单机版安装2、集群安装3、配置参数解读(zoo.cfg)4、ZK集群启动脚本 三、命令行操作1、语法2、使用3、节点相关4、监听器原理5、节点删除与查看 三、写数据流程 一、简介 1、工作机制 官…

输电线路故障数据集(单相接地故障、两相接地故障、两相间短路故障、三相间短路故障)

1.数据集介绍 将故障区分为具体的不同类型&#xff1a;单相短路故障、两相接地短路故障、两相相间故障、三相相间短路故障。每类有1300行数据左右&#xff0c;这里随意举出每种类别的两个样本进行展示。 GCBAIaIbIcVaVbVc1001-151.2918124-9.67745156385.800162260.400749853…

Hadoop设置固定ip无效的解决办法

今天配置Hadoop的时候&#xff0c;执行vi /etc/sysconfig/network-scripts/ifcfg-ens33修改网络配置文件后&#xff0c;一切正常&#xff0c;但重启后IP改变了&#xff0c;并且在修改以及重启网络连接数次后&#xff0c;IP依旧不按照我在ifcfg-ens33中配置的那样&#xff0c;检…

C++ - map 的 例题

前言 本博客在 一下文章关于 map 和 set 讲解之下&#xff0c;对 map 当中的 operator[] &#xff08;&#xff09;函数的功能运用&#xff0c;感受 map 功能强大。 349. 两个数组的交集 - 力扣&#xff08;LeetCode&#xff09; 给定两个数组 nums1 和 nums2 &#xff0c;返回…