当前位置: 首页 > news >正文

《HeadFirst设计模式(第二版)》第九章代码——迭代器模式

情景:

        一家早餐店和一家午餐点准备合并在一起,两家的点菜的菜单实现方式如下:

        首先,他们的菜单选项都基于同一个类:

菜单选项类

package Chapter9_IteratorPattern.Origin;/*** @Author 竹心* @Date 2023/8/17**/public class MenuItem {String name;String description;boolean vegetarian;double price;public MenuItem(String name,String description,boolean vegetarian,double price){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;}
}

早餐店初始菜单

package Chapter9_IteratorPattern.Origin;import java.util.ArrayList;
import java.util.List;/*** @Author 竹心* @Date 2023/8/17**/public class PancakeHouseMenu {List<MenuItem> menuItems;public PancakeHouseMenu(){this.menuItems = new ArrayList<MenuItem>();addItem("K&B's Pancake Breakfast","Pancake with scrambled eggs and toast",true,2.99);addItem("Regular Pancake Breakfast","Pancake with fired eggs, sausage",false,2.99);addItem("BlueBerry Pancake","Pancake made with fresh blueberries",true,3.49);addItem("Waffles","Waffles with your choice of blueberries of strawberries",true,3.59);}public void addItem(String name,String description,boolean vegetarian,double price){MenuItem menuItem = new MenuItem(name,description,vegetarian,price);this.menuItems.add(menuItem);}public List<MenuItem> getMenuItems(){return this.menuItems;}
}

午餐店初始菜单:

package Chapter9_IteratorPattern.Origin;/*** @Author 竹心* @Date 2023/8/17**/public class DinerMenu {static final int MAX_ITEMS = 6;int numberOfItems = 0;MenuItem[] menuItems;public DinerMenu(){this.menuItems = new MenuItem[MAX_ITEMS];addItem("aaa","food1",true,2.99);addItem("bbb","food2",true,2.99);addItem("ccc","food3",true,3.29);addItem("ddd","food4",true,3.05);}public void addItem(String name,String description,boolean vegetarian,double price){MenuItem menuItem = new MenuItem(name,description,vegetarian,price);if(this.numberOfItems >= MAX_ITEMS){System.out.println("Sorry! Menu is full!");}else{this.menuItems[this.numberOfItems] = menuItem;this.numberOfItems++;}}public MenuItem[] getMenuItems(){return this.menuItems;}
}

可以得知:前者使用List来实现,后者使用数组来实现。

这时候,如果不采取任何方法加以更改,新餐厅的服务员将要这样使用两个菜单:

服务员类初始

package Chapter9_IteratorPattern.Origin;import java.util.List;/*** @Author 竹心* @Date 2023/8/17**/public class Waitress {public void printMenu(){//遍历菜单PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();List<MenuItem> breakfastItems = pancakeHouseMenu.getMenuItems();DinerMenu dinerMenu = new DinerMenu();MenuItem[] lunchItems = dinerMenu.getMenuItems();for(int i= 0;i<breakfastItems.size();++i){MenuItem menuItem = breakfastItems.get(i);System.out.println(menuItem.getName()+"  ");System.out.println(menuItem.getPrice()+"  ");System.out.println(menuItem.getDescription()+"  ");}for(int i = 0;i<lunchItems.length;++i){MenuItem menuItem = lunchItems[i];System.out.println(menuItem.getName()+"  ");System.out.println(menuItem.getPrice()+"  ");System.out.println(menuItem.getDescription()+"  ");}}public static void main(String[] args) {Waitress waitress = new Waitress();waitress.printMenu();}
}

由此可见:服务员类和两个菜单类直接接触,既违反封装原理,还违背了面向接口编码的原理,同时极其不利于维护。

迭代器模式

这时可以采用迭代器模式:在两个菜单和服务员之间加入一个迭代器(iterator),迭代器负责直接处理菜单的遍历等功能,然后服务员通过这个迭代器来使用菜单,成功解耦。

简介

        迭代器提供一种方式,可以访问一个聚合对象中的元素而又不暴露其潜在实现。

        同时把遍历的任务放到迭代器上而不是聚合上,这就简化了聚合的接口和实现(让聚合只需负责管理对象集合即可),满足单一责任原则。

自定义的迭代器

自定义迭代器接口

package Chapter9_IteratorPattern.MyIterator;/*** @Author 竹心* @Date 2023/8/17**/public interface Iterator {//提供一个统一的迭代器接口,在用户和对象集合之间加入迭代器,//迭代器中含有遍历集合的具体操作,不需要关心如何实现boolean hasNext();MenuItem next();
}

早餐迭代器:

package Chapter9_IteratorPattern.MyIterator;import java.util.List;/*** @Author 竹心* @Date 2023/8/17**/public class PancakeHouseIterator implements Iterator{List<MenuItem> items;int position = 0;public PancakeHouseIterator(List<MenuItem> items){this.items = items;}@Overridepublic MenuItem next() {MenuItem menuItem = items.get(position);position++;return menuItem;}@Overridepublic boolean hasNext() {if(position >= items.size() || items.get(position) == null){return false;}else{return true;}}
}

使用迭代器的早餐菜单

加入一个新方法即可:

    public Iterator createIterator(){return new PancakeHouseIterator(menuItems);}

午餐迭代器:

package Chapter9_IteratorPattern.MyIterator;/*** @Author 竹心* @Date 2023/8/17**/public class DinerMenuIterator implements Iterator{MenuItem[] items;int position = 0;public DinerMenuIterator(MenuItem[] items){this.items = items;}@Overridepublic MenuItem next() {MenuItem menuItem = items[position];position++;return menuItem;}@Overridepublic boolean hasNext() {if(position >= items.length || items[position] == null){return false;}else{return true;}}
}

使用迭代器的午餐菜单:

同理:

    public Iterator createIterator(){//提供一个接口使得迭代器获取到该集合return new DinerMenuIterator(menuItems);}

使用自定义迭代器的服务员类:

package Chapter9_IteratorPattern.MyIterator;/*** @Author 竹心* @Date 2023/8/17**/public class Waitress {PancakeHouseMenu pancakeHouseMenu;DinerMenu dinerMenu;public Waitress(PancakeHouseMenu pancakeHouseMenu,DinerMenu dinerMenu){this.pancakeHouseMenu = pancakeHouseMenu;this.dinerMenu = dinerMenu;}public void printMenu(){Iterator pancakeMenuIterator = pancakeHouseMenu.createIterator();Iterator dinerIterator = dinerMenu.createIterator();System.out.println("MENU\n----\nBREAKFAST");printMenu(pancakeMenuIterator);System.out.println("\nLUNCH");printMenu(dinerIterator);}private void printMenu(Iterator iterator){while(iterator.hasNext()){MenuItem menuItem = iterator.next();System.out.println(menuItem.getName()+"  ");System.out.println(menuItem.getPrice()+"  ");System.out.println(menuItem.getDescription()+"  ");}}
}

测试类:

package Chapter9_IteratorPattern.MyIterator;/*** @Author 竹心* @Date 2023/8/17**/public class MenuTestDrive {public static void main(String[] args) {PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();DinerMenu dinerMenu = new DinerMenu();Waitress waitress = new Waitress(pancakeHouseMenu,dinerMenu);waitress.printMenu();}
}

使用JAVA自带的迭代器

因为早餐菜单使用了ArrayList,它有iterator()方法返回一个迭代器(所以这里可以删除掉它的自定义迭代器),然而午餐菜单是用数组实现的,没有这个方法,所以午餐类还是需要使用自定义的迭代器(“继承”于java的迭代器)。

修改早餐类:

添加头文件:

import java.util.Iterator;

然后修改方法:

    public Iterator<MenuItem> createIterator(){return menuItems.iterator();}

修改午餐迭代器类:

package Chapter9_IteratorPattern.JavaIterator;
import java.util.Iterator;/*** @Author 竹心* @Date 2023/8/17**/public class DinerMenuIterator implements Iterator<MenuItem>{MenuItem[] items;int position = 0;public DinerMenuIterator(MenuItem[] items){this.items = items;}@Overridepublic MenuItem next() {MenuItem menuItem = items[position];position++;return menuItem;}@Overridepublic boolean hasNext() {if(position >= items.length || items[position] == null){return false;}else{return true;}}@Overridepublic void remove() {//java自带的迭代器是由remove()方法的,所以这里必须要实现throw new UnsupportedOperationException("you can not remove it!");}
}

添加Menu接口:

package Chapter9_IteratorPattern.JavaIterator;import java.util.Iterator;/*** @Author 竹心* @Date 2023/8/18**/public interface Menu {public Iterator<?> createIterator();
}

记得分别在午餐菜单类和早餐菜单类的类声明那里加上对Menu的实现:

public class DinerMenu implements Menu{...}public class PancakeHouseMenu implements Menu{...}

修改服务员类:

package Chapter9_IteratorPattern.JavaIterator;
import java.util.Iterator;
/*** @Author 竹心* @Date 2023/8/17**/public class Waitress {Menu pancakeHouseMenu;Menu dinerMenu;public Waitress(Menu pancakeHouseMenu,Menu dinerMenu){this.pancakeHouseMenu = pancakeHouseMenu;this.dinerMenu = dinerMenu;}public void printMenu(){Iterator<?> pancakeMenuIterator = pancakeHouseMenu.createIterator();Iterator<?> dinerIterator = dinerMenu.createIterator();System.out.println("MENU\n----\nBREAKFAST");printMenu(pancakeMenuIterator);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()+"  ");}}
}

情景扩展1

        好了,现在又有一家咖啡店并入餐厅,并在晚上提供服务,这家咖啡店也有它独特的菜单实现方式:使用哈希表!接下来要将它加入迭代器的使用中(这里将其称为晚餐菜单):

使用JAVA自带迭代器的晚餐菜单:

package Chapter9_IteratorPattern.AddCafe;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;/*** @Author 竹心* @Date 2023/8/18**/public class CafeMenu implements Menu{HashMap<String, MenuItem> menuItems = new HashMap<String, MenuItem>();public CafeMenu() {addItem("Veggie Burger and Air Fries","Veggie burger on a whole wheat bun, lettuce, tomato, and fries",true, 3.99);addItem("Soup of the day","A cup of the soup of the day, with a side salad",false, 3.69);addItem("Burrito","A large burrito, with whole pinto beans, salsa, guacamole",true, 4.29);}public void addItem(String name, String description,boolean vegetarian, double price){MenuItem menuItem = new MenuItem(name, description, vegetarian, price);menuItems.put(name, menuItem);}//    public Map<String, MenuItem> getItems() {
//        return menuItems;
//    }public Iterator<MenuItem> createIterator() {//获取哈希表中的集合的迭代器return menuItems.values().iterator();}
}

修改后的服务员类:

package Chapter9_IteratorPattern.AddCafe;import java.util.Iterator;
/*** @Author 竹心* @Date 2023/8/17**/public class Waitress {Menu pancakeHouseMenu;Menu dinerMenu;Menu cafeMenu;public Waitress(Menu pancakeHouseMenu, Menu dinerMenu, Menu cafeMenu){this.pancakeHouseMenu = pancakeHouseMenu;this.dinerMenu = dinerMenu;this.cafeMenu = cafeMenu;}public void printMenu(){Iterator<?> pancakeMenuIterator = pancakeHouseMenu.createIterator();Iterator<?> dinerIterator = dinerMenu.createIterator();Iterator<?> cafeIterator = cafeMenu.createIterator();System.out.println("MENU\n----\nBREAKFAST");printMenu(pancakeMenuIterator);System.out.println("\nLUNCH");printMenu(dinerIterator);System.out.println("\nDINNER");printMenu(cafeIterator);}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()+"  ");}}
}

        现在,我们发现,如果菜单越来越多,服务员类涉及到的操作也越来越多,所以这里可以对服务员类进行优化:

优化后的服务员类

package headfirst.designpatterns.iterator.transition;
import java.util.*;/*** @Author 竹心* @Date 2023/8/18**/public class Waitress {ArrayList<Menu> menus;public Waitress(ArrayList<Menu> menus) {this.menus = menus;}public void printMenu() {Iterator<?> menuIterator = menus.iterator();while(menuIterator.hasNext()) {Menu menu = (Menu)menuIterator.next();printMenu(menu.createIterator());}}void printMenu(Iterator<?> iterator) {while (iterator.hasNext()) {MenuItem menuItem = (MenuItem)iterator.next();System.out.print(menuItem.getName() + ", ");System.out.print(menuItem.getPrice() + " -- ");System.out.println(menuItem.getDescription());}}
}  

情景扩展2

        现在问题来了,如果菜单中存在子菜单,那么又该如何实现呢?

        很明显上面的方法已经不适用了,重写菜单代码才行。

        这里就引出了组合模式:

《HeadFirst设计模式(第二版)》第九章代码——组合模式_轩下小酌的博客-CSDN博客

相关文章:

《HeadFirst设计模式(第二版)》第九章代码——迭代器模式

情景&#xff1a; 一家早餐店和一家午餐点准备合并在一起&#xff0c;两家的点菜的菜单实现方式如下: 首先&#xff0c;他们的菜单选项都基于同一个类&#xff1a; 菜单选项类 package Chapter9_IteratorPattern.Origin;/*** Author 竹心* Date 2023/8/17**/public class Men…...

Electron入门,项目启动。

electron 简单介绍&#xff1a; 实现&#xff1a;HTML/CSS/JS桌面程序&#xff0c;搭建跨平台桌面应用。 electron 官方文档&#xff1a; [https://electronjs.org/docs] 本文是基于以下2篇文章且自行实践过的&#xff0c;可行性真实有效。 文章1&#xff1a; https://www.cnbl…...

深入理解索引B+树的基本原理

目录 1. 引言 2. 为什么要使用索引&#xff1f; 3. 索引的概述 4. 索引的优点是什么&#xff1f; 4.1 降低数据库的IO成本&#xff0c;提高数据查找效率 4.2 保证数据库每一行数据的唯一性 4.3 加速表与表之间的连接 4.4 减少查询中分组与排序的执行时间 5. 索引的缺点…...

vue3 简易用对话框实现点击头像放大查看

设置头像悬停手势 img:hover{cursor: pointer;}效果&#xff1a; 编写对话框 <el-dialog class"bigAvatar"style"border-radius: 4px;"v-model"deleteDialogVisible"title"查看头像"top"5px"><div><img src&…...

opencv 矩阵运算

1.矩阵乘&#xff08;*&#xff09; Mat mat1 Mat::ones(2,3,CV_32FC1);Mat mat2 Mat::ones(3,2,CV_32FC1);Mat mat3 mat1 * mat2; //矩阵乘 结果 2.元素乘法或者除法&#xff08;mul&#xff09; Mat m Mat::ones(2, 3, CV_32FC1);m.at<float>(0, 1) 3;m.at…...

第四章 字符串part01

344.反转字符串 public void reverseString(char[] s) {int len s.length;int left 0;int right len-1;while (left < right){char tmp s[right];s[right] s[left];s[left] tmp;left;right--;} }反转字符串II 注意String不可变&#xff0c;因此可使用char数组或者St…...

Python3内置函数大全

吐血整理 Python3内置函数大全 1.abs()函数2.all()函数3.any()函数4.ascii()函数5.bin()函数6.bool()函数7.bytes()函数8.challable()函数9.chr()函数10.classmethod()函数11.complex()函数12.complie()函数13.delattr()函数14.dict()函数15.dir()函数16.divmod()函数17.enumer…...

什么是“新型基础设施”?建设重点是什么?

一是信息基础设施。主要是指基于新一代信息技术演化生成的基础设施&#xff0c;比如&#xff0c;以5G、物联网、工业互联网、卫星互联网为代表的通信网络基础设施&#xff0c;以人工智能、云计算、区块链等为代表的新技术基础设施&#xff0c;以数据中心、智能计算中心为代表的…...

混杂接口模式---vlan

策略在两个地方可以用--1、重发布 2、bgp邻居 2、二层可以干的&#xff0c;三层也可以干 3、未知单播&#xff1a;交换机的MAC地址表的记录保留时间是5分钟&#xff0c;电脑的ARP表的记录保留时间是2小时 4、route recursive-lookup tunnel 华为默认对于bgp学习来的路由不开启标…...

Greenplum多级分区表添加分区报错ERROR: no partitions specified at depth 2

一般来说&#xff0c;我们二级分区表都会使用模版&#xff0c;如果没有使用模版特性&#xff0c;那么就会报ERROR: no partitions specified at depth 2类似的错误。因为没有模版&#xff0c;必须要显式指定分区。 当然我们在建表的时候&#xff0c;如果没有指定&#xff0c;那…...

EV PV AC SPI CPI TCPI

SPI EV / PV CPI EV / ACCPI 1.25 SPI 0.8 PV 10 000 BAC 100 000EV PV * SPI 10 000 * 0.8 8000 AC EV / CPI 8000 / 1.25 6400TCPI (BAC - EV) / (BAC -AC) (100 000 - 8 000) / (100 000 - 6 400) 92 000 / 93 600 0.98290598...

【电商领域】Axure在线购物商城小程序原型图,品牌自营垂直电商APP原型

作品概况 页面数量&#xff1a;共 60 页 兼容软件&#xff1a;Axure RP 9/10&#xff0c;不支持低版本 应用领域&#xff1a;网上商城、品牌自营商城、商城模块插件 作品申明&#xff1a;页面内容仅用于功能演示&#xff0c;无实际功能 作品特色 本作品为品牌自营网上商城…...

Cpp基础Ⅰ之编译、链接

1 C是如何工作的 工具&#xff1a;Visual Studio 1.1 预处理语句 在.cpp源文件中&#xff0c;所有#字符开头的语句为预处理语句 例如在下面的 Hello World 程序中 #include<iostream>int main() {std::cout <"Hello World!"<std::endl;std::cin.get…...

用户新增预测(Datawhale机器学习AI夏令营第三期)

文章目录 简介任务1&#xff1a;跑通Baseline实操并回答下面问题&#xff1a;如果将submit.csv提交到讯飞比赛页面&#xff0c;会有多少的分数&#xff1f;代码中如何对udmp进行了人工的onehot&#xff1f; 任务2.1&#xff1a;数据分析与可视化编写代码回答下面的问题&#xf…...

RGOS日常管理操作

RGOS日常管理操作 一、前言二、RGOS平台概述2.1、锐捷设备的常用登陆方式2.2、使用Console登入2.3、Telnet远程管理2.4、SSH远程管理2.5、登陆软件&#xff1a;SecureCRT 三、CLI命令行操作3.1、CLI命令行基础3.2、CLI模式3.3、CLI模式互换3.4、命令行特性3.4.1、分屏显示3.4.2…...

阿里云使用WordPress搭建个人博客

手把手教你使用阿里云服务器搭建个人博客 一、免费创建服务器实例 1.1 点击试用 点击试用会需要你创建服务器实例&#xff0c;直接选择默认的操作系统即可&#xff0c;点击下一步 1.2 修改服务器账号密码 二、创建云数据库实例 2.1 免费获取云数据库使用 2.2 实例列表页 在…...

供应链安全和第三方风险管理:讨论如何应对供应链中的安全风险,以及评估和管理第三方合作伙伴可能带来的威胁

第一章&#xff1a;引言 在当今数字化时代&#xff0c;供应链的安全性越来越受到重视。企业的成功不仅仅依赖于产品和服务的质量&#xff0c;还取决于供应链中的安全性。然而&#xff0c;随着供应链越来越复杂&#xff0c;第三方合作伙伴的参与也带来了一系列安全风险。本文将…...

《Java极简设计模式》第04章:建造者模式(Builder)

作者&#xff1a;冰河 星球&#xff1a;http://m6z.cn/6aeFbs 博客&#xff1a;https://binghe.gitcode.host 文章汇总&#xff1a;https://binghe.gitcode.host/md/all/all.html 源码地址&#xff1a;https://github.com/binghe001/java-simple-design-patterns/tree/master/j…...

Go download

https://go.dev/dl/https://golang.google.cn/dl/...

2023年Java核心技术面试第四篇(篇篇万字精讲)

目录 八. 对比Vector&#xff0c;ArrayList, LinkedList有何区别&#xff1f; 8.1 典型回答 8.1.1 Vector&#xff1a; 8.1.2 ArrayList &#xff1a; 8.1.3 LinkedList 8.2 考察点分析&#xff1a; 8.2.1 不同容器类型适合的场景 八. 对比Vector&#xff0c;ArrayList, Linke…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...