设计模式浅析(十) ·设计模式之迭代器组合模式

设计模式浅析(十) ·设计模式之迭代器&组合模式

日常叨逼叨

java设计模式浅析,如果觉得对你有帮助,记得一键三连,谢谢各位观众老爷😁😁


案例

有两家门店,门店A呢只提供早餐,门店B呢只提供午餐,有一天这两家店铺想要进行合并,一起做大做强,再创辉煌。

合并后呢,对于菜单的定制存在了一定的问题:

门店A的菜单采用了ArrayList进行存储,但是门店B的菜单之前是采用了数组进行存储,那么在合并之后,对于服务员来说,怎么才能将菜单展示出来,是一件比较头疼的事情

旧的门店A的菜单构成:

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/2/29 14:37
 * @注释 A餐馆的馅饼菜单
 */
public class PanCakeMenu {
    private ArrayList menuItems;

    public PanCakeMenu() {
        menuItems = new ArrayList<>();

        addItem("K&B PanCake", "PanCake with eggs and beef", true, 18.0);
        addItem("normal PanCake", "PanCake with eggs", true, 10.0);
        addItem("blueberry PanCake", "PanCake with blue and cheese", false, 13.0);
    }

    private void addItem(String name, String disc, boolean vegetarian, double price) {

        menuItems.add(new MenuItem(name, disc, vegetarian, price));

    }
    public ArrayList getMenuItems() {
        return menuItems;
    }
}

旧的门店B的菜单组成:

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/2/29 14:37
 * @注释 B餐馆的午餐菜单
 */
public class LunchMenu {
    static final Integer MAX_VALUE = 3;
    int index = 0;
    private MenuItem[] menuItems;

    public LunchMenu() {
        menuItems = new MenuItem[MAX_VALUE];

        addItem("single lunch", "hot dog with coke", true, 18.0);
        addItem("soup", "soup with cake for lunch", true, 19.0);
        addItem("Tomato and egg rice bowl", "rice with Tomato and egg for lunch", true, 21.0);
    }

    private void addItem(String name, String disc, boolean vegetarian, double price) {
        if (menuItems.length > MAX_VALUE) {
            System.out.println("menu is full, not allowed to insert !");
        } else {
            menuItems[index] = new MenuItem(name, disc, vegetarian, price);
            index++;
        }
    }

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

那么对于服务员来说,在合并门店之后,如果实现简单的菜单组合,服务员代码可能如下

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/2/29 15:01
 * @注释 合并后的B餐厅的waiter
 */
public class Waiter {
    private PanCakeMenu panCakeMenu;
    private LunchMenu lunchMenu;

    public Waiter(PanCakeMenu panCakeMenu, LunchMenu lunchMenu) {
        this.panCakeMenu = panCakeMenu;
        this.lunchMenu = lunchMenu;
    }

    public void showMenu() {
        //展示菜单
        ArrayList menuItems = panCakeMenu.getMenuItems();
        MenuItem[] menuItems1 = lunchMenu.getMenuItems();

        for (int i = 0; i < menuItems.size(); i++) {
            MenuItem a = (MenuItem) menuItems.get(i);
            System.out.println(a.toString());
        }

        for (int i = 0; i < menuItems1.length; i++) {
            MenuItem MenuItem = menuItems1[i];
            System.out.println(MenuItem.toString());
        }
    }

}

运行结果:

breakfast-
MenuItem{name=‘K&B PanCake’, disc=‘PanCake with eggs and beef’, vegetarian=true, price=18.0}
MenuItem{name=‘normal PanCake’, disc=‘PanCake with eggs’, vegetarian=true, price=10.0}
MenuItem{name=‘blueberry PanCake’, disc=‘PanCake with blue and cheese’, vegetarian=false, price=13.0}
lunch-
MenuItem{name=‘single lunch’, disc=‘hot dog with coke’, vegetarian=true, price=18.0}
MenuItem{name=‘soup’, disc=‘soup with cake for lunch’, vegetarian=true, price=19.0}
MenuItem{name=‘Tomato and egg rice bowl’, disc=‘rice with Tomato and egg for lunch’, vegetarian=true, price=21.0}

虽然呢,对于服务员来说,貌似实现了这个showmenu()这个功能,但是如果后期再加入一个门店,是不是又得写一个循环去进行第三家门店菜单的遍历?

那么有没有办法进行优化一些呢?

我们来进行分析一下:

  1. 要遍历早餐项,我们需要使用ArrayListsize()get()方法

  2. 要遍历午餐项,我们需要使用数组length字段和中括号[]

  3. 现在我们创建一个对象,将它称为迭代器(Iterator),利用它来封装“遍历集合内的每个对象的过程”。先让我们在ArrayList上试试:

    Iterator iterator1 = panCakeMenu.createIterator();
    while (iterator1.hasNext()) {
                System.out.println(iterator1.next().toString());
            }
    
  4. 然后在数组上试一试:

MealIterator iterator = lunchMenu.createIterator();
while (iterator.hasNext()){
            System.out.println(iterator.next().toString());
        }

那么我们创建一个MealIterator迭代器,暂时为lunchMenu服务

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/2/29 15:11
 * @注释 MealIterator
 */
public class MealIterator implements Iterator {
    private MenuItem[] menuItems;
    private int index = 0;

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

    @Override
    public boolean hasNext() {
        if (menuItems.length <= index||menuItems[index]==null) {
            return false;
        } else
            return true;
    }

    @Override
    public Object next() {

        MenuItem menuItem = menuItems[index];
        index++;
        return menuItem;
    }

    @Override
    public void remove() {
        if (index < 0) {
            throw new IllegalArgumentException("list is empty,no element can be removed !");
        }
        if (menuItems[index - 1] != null) {
            for (int i = index - 1; i < (menuItems.length - 1); i++) {
                menuItems[i] = menuItems[i + 1];
            }
            menuItems[index - 1] = null;
        }

    }
}

使用上述的迭代器,重构菜单

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/2/29 14:37
 * @注释 B餐馆的午餐菜单
 */
public class LunchMenu {
    static final Integer MAX_VALUE = 5;
    int index = 0;
    private MenuItem[] menuItems;

    public LunchMenu() {
        menuItems = new MenuItem[MAX_VALUE];
        addItem("single lunch", "hot dog with coke", true, 18.0);
        addItem("soup", "soup with cake for lunch", true, 19.0);
        addItem("Tomato and egg rice bowl", "rice with Tomato and egg for lunch", true, 21.0);
    }

    private void addItem(String name, String disc, boolean vegetarian, double price) {
        if (menuItems.length > MAX_VALUE) {
            System.out.println("menu is full, not allowed to insert !");
        } else {
            menuItems[index] = new MenuItem(name, disc, vegetarian, price);
            index++;
        }
    }
    public MealIterator createIterator() {
        return new MealIterator(menuItems);
    }
}

相应的,服务员类也进行重构

/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/2/29 15:01
 * @注释 合并后的B餐厅的waiter
 */
public class Waiter {
    private PanCakeMenu panCakeMenu;
    private LunchMenu lunchMenu;

    public Waiter(PanCakeMenu panCakeMenu, LunchMenu lunchMenu) {
        this.panCakeMenu = panCakeMenu;
        this.lunchMenu = lunchMenu;
    }

    public void showMenu() {
        //展示菜单

        Iterator iterator1 = panCakeMenu.createIterator();
        MealIterator iterator = lunchMenu.createIterator();
        System.out.println("breakfast-");
        showMenu(iterator1);
        System.out.println("lunch-");
        showMenu(iterator);
    }

    public void showMenu(Iterator iterator) {
        while (iterator.hasNext()) {
            System.out.println(iterator.next().toString());
        }
    }
}

这个选代器让服务员能够从具体类的实现中解耦。她不需要知道菜单是使用数组、ArrayList,还是便利贴来实现。她只关心她能够取得选代器。

但是对于服务员来说,他还持有两个接口的具体实现类,有点违背了我们面向接口编程而不是面向接口的实现编程这一原则,我们在重构一下代码。

  • 创建Menu接口
/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/2/29 14:37
 * @注释 menu 公共接口
 */
public interface Menu {
    Iterator createIterator();
}
  • PanCakeMenuLunchMenu实现接口
/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/2/29 14:37
 * @注释 B餐馆的午餐菜单
 */
public class LunchMenu implements Menu{
    static final Integer MAX_VALUE = 5;
    int index = 0;
    private MenuItem[] menuItems;

    public LunchMenu() {
        menuItems = new MenuItem[MAX_VALUE];

        addItem("single lunch", "hot dog with coke", true, 18.0);
        addItem("soup", "soup with cake for lunch", true, 19.0);
        addItem("Tomato and egg rice bowl", "rice with Tomato and egg for lunch", true, 21.0);
    }

    private void addItem(String name, String disc, boolean vegetarian, double price) {
        if (menuItems.length > MAX_VALUE) {
            System.out.println("menu is full, not allowed to insert !");
        } else {
            menuItems[index] = new MenuItem(name, disc, vegetarian, price);
            index++;
        }
    }

    public Iterator createIterator() {
        return new MealIterator(menuItems);
    }
}
  • 让服务员持有接口Menu
/**
 * @version 1.0
 * @Author jerryLau
 * @Date 2024/2/29 15:01
 * @注释 合并后的B餐厅的waiter
 */
public class Waiter {
    private Menu panCakeMenu;
    private Menu lunchMenu;

    public Waiter(Menu panCakeMenu, Menu lunchMenu) {
        this.panCakeMenu = panCakeMenu;
        this.lunchMenu = lunchMenu;
    }

    public void showMenu() {
        //展示菜单

        Iterator iterator1 = panCakeMenu.createIterator();
        Iterator iterator = lunchMenu.createIterator();
        System.out.println("breakfast-");
        showMenu(iterator1);
        System.out.println("lunch-");
        showMenu(iterator);
    }

    public void showMenu(Iterator iterator) {
        while (iterator.hasNext()) {
            System.out.println(iterator.next().toString());
        }
    }
}

你可能会奇怪,为什么我们不使用Java的Iterator接口呢–我们之所以这么做,是为了要让你了解如何从头创建一个迭代器。现在目的达到了,如果再有店铺合并,可以使用java的Iterator接口。

迭代器模式

Java设计模式中的迭代器模式介绍

迭代器模式是一种行为型设计模式,它提供了一种方法来顺序访问一个聚合对象中的各个元素,而无需知道或暴露该对象的内部表示。在Java中,迭代器模式是通过java.util.Iterator接口来实现的。

元素

迭代器模式涉及以下几个主要的元素:

  1. 迭代器(Iterator):这是一个接口或抽象类,它定义了访问和遍历聚合对象中的元素的方法。在Java中,这通常是一个名为iterator()的方法,它返回一个实现了Iterator接口的对象。
  2. 具体迭代器(ConcreteIterator):这是迭代器接口的具体实现。它负责遍历聚合对象中的元素,并提供了获取下一个元素、检查是否还有更多元素等方法。
  3. 聚合(Aggregate):这是一个接口或抽象类,它定义了创建迭代器对象的方法。在Java中,这通常是一个名为iterator()的方法。
  4. 具体聚合(ConcreteAggregate):这是聚合接口的具体实现。它实现了创建迭代器对象的方法,并返回与聚合对象相关联的具体迭代器。
优缺点
优点
  1. 简化遍历:迭代器模式提供了一种简单的方式来遍历聚合对象中的元素,而无需了解聚合对象的底层表示。
  2. 多种遍历方式:通过实现不同的迭代器类,可以为同一个聚合对象提供多种遍历方式。
  3. 封装性:使用迭代器模式,客户端代码只需要知道如何使用迭代器,而无需关心聚合对象的内部实现。
缺点
  1. 增加类的数量:由于迭代器模式将存储数据和遍历数据的职责分离,每个聚合类可能需要对应一个迭代器类,这可能会增加系统的复杂性。
  2. 遍历效率:对于简单的聚合对象(如数组或有序列表),使用迭代器进行遍历可能比直接访问元素更加繁琐和效率低下。
适用场景

迭代器模式通常适用于以下场景:

  1. 需要遍历聚合对象的场景,而又不希望客户端代码了解聚合对象的底层表示。
  2. 需要为聚合对象提供多种遍历方式的场景。
  3. 需要统一遍历接口的场景,以简化客户端代码。
  4. 在Java中,java.util.Iterator 接口就是迭代器模式的实现。当你有一个集合(如 ListSet 等)并想要遍历其中的元素时,你可以使用迭代器。

正当我们觉得这样很周全时,突然又有一个新的需求,店家B想在午餐的菜单中添加一种午后甜点的“子菜单”

如果我们能让甜点菜单变成餐厅菜单集合的一个元素,那该有多好。但是根据现在的实现,根本做不到。

上述需求类似于这样:

请添加图片描述

那么我们不得不考虑用一些新的设计,因为我们需要表现菜单、嵌套子菜单和菜单项,我们很自然地采用树形结构以便符合这样的需求

所以,在我们的新设计中,真正需要些什么呢?
我们需要某种树形结构,可以容纳菜单、子菜单和菜单项。
我们需要确定能够在每个菜单的各个项之间游走,而且至少要像现在用迭代器一样方便。
我们也需要能够更有弹性地在菜单项之间游走。比方说,可能只需要遍历甜点菜单,或者可以遍历餐厅的整个菜单(包括甜点菜单在内)

没错,我们要介绍另一个模式解决这个难题。我们并没有放弃迭代器–它仍然是我们解决方案中的一部分–然而,管理菜单的问题已经到了一个迭代器无法解决的新维度。所以,我们将倒退几步,改用组合模式(Composite Pattern)来实现这一部分。
对于这个模式,我们不打算深入探讨,只在这里提出它的正式定义:

组合模式

**定义:**组合模式允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。

类图

请添加图片描述

我们要如何在菜单上应用组合模式呢?一开始,我们需要创建一个组件接口来作为菜单和菜单项的共同接口,让我们能够用统一的做法来处理菜单和菜单项。换句话说,我们可以针对菜单或菜单项调用相同的方法。

首先可以创建菜单组件

public abstract class MenuComponent {
    //操作 range start
    public void add(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public void remove(MenuComponent menuComponent) {
        throw new UnsupportedOperationException();
    }

    public MenuComponent getChild(int i) {
        throw new UnsupportedOperationException();
    }
    //操作 range end

    //基本属性 range start
    public String getName() {
        throw new UnsupportedOperationException();
    }

    public String getDescription() {
        throw new UnsupportedOperationException();
    }

    public double getPrice() {
        throw new UnsupportedOperationException();
    }

    public boolean isVegetarian() {
        throw new UnsupportedOperationException();
    }

    public void print() {
        throw new UnsupportedOperationException();
    }
    //基本属性 range end
}

然后创建菜单项继承菜单组件

public class MenuItem extends MenuComponent {
    private String name;
    private String description;
    private double price;
    private boolean isVegetarian;

    public MenuItem(String name, String description, double price, boolean isVegetarian) {
        this.name = name;
        this.description = description;
        this.price = price;
        this.isVegetarian = isVegetarian;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public double getPrice() {
        return price;
    }

    @Override
    public boolean isVegetarian() {
        return isVegetarian;
    }

    @Override
    public void print() {
        System.out.println(" " + getName() + (isVegetarian() ? "(N)" : "(Y)") + " " + getDescription() + " " + getPrice() + " ");
    }
}

同样创建菜单,也是继承自菜单组件

public class Menu extends MenuComponent {
    List<MenuComponent> menuComponents = new ArrayList<MenuComponent>();
    private String name;
    private String description;


    public Menu(String name, String description) {
        this.name = name;
        this.description = description;

    }

    @Override
    public void add(MenuComponent menuComponent) {
        menuComponents.add(menuComponent);
    }

    @Override
    public void remove(MenuComponent menuComponent) {
        menuComponents.remove(menuComponent);
    }

    @Override
    public MenuComponent getChild(int i) {
        return menuComponents.get(i);
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getDescription() {
        return description;
    }


    @Override
    public void print() {
        System.out.println(" " + getName()+" " + getDescription());
        System.out.println("---------------------------");

        Iterator<MenuComponent> iterator = menuComponents.iterator();
        while (iterator.hasNext()) {
            MenuComponent next = iterator.next();
            next.print();
        }


    }
}

那么对于服务员来说,可以进行以下修改

public class Waiter {
    MenuComponent allMenus;

    public Waiter(MenuComponent allMenus) {
        this.allMenus = allMenus;
    }

    public void printMenu() {
        allMenus.print();
    }
}

创建测试类

public class MenuTestDriver {
    public static void main(String[] args) {
        MenuComponent menuComponentA = new Menu("PANCAKE HOUSE MENU", "Breakfast");
        MenuComponent menuComponentB = new Menu("LUNCH MENU", "Lunch");
        MenuComponent innerMenu = new Menu("LUNCH inner MENU", "Dessert of Lunch ");
        MenuComponent allMenus = new Menu("ALL MENUS", "All menus combined");

        allMenus.add(menuComponentA);
        allMenus.add(menuComponentB);

        menuComponentB.add(new MenuItem("蛋炒饭", "蛋炒饭:米饭,鸡蛋", 15.0, false));
        menuComponentB.add(innerMenu);
        innerMenu.add(new MenuItem("甜点", "饭后甜点", 1.5, true));
        innerMenu.add(new MenuItem("水果", "饭后水果", 5.0, true));

        Waiter waiter = new Waiter(allMenus);
        waiter.printMenu();

    }

}

运行结果

请添加图片描述

至此,我们通过了组合模式,实现了菜单的管理

下面我们一起来总结以下组合模式相关的内容

元素

组合模式主要包含三个要素:

  1. 抽象根节点(Component):定义系统各层次对象的共有方法和属性,可以预先定义一些默认行为和属性。在抽象根节点中,通常会定义访问及管理其子构件的方法,如增加子节点、删除子节点、获取子节点等。
  2. 叶子节点(Leaf):叶子节点对象,其下再无分支,是系统层次遍历的最小单位。在组合结构中,叶子节点没有子节点,它实现了在抽象根节点中定义的行为。
  3. 树枝节点(Composite):定义树枝节点的行为,存储子节点,组合树枝节点和叶子节点形成一个树形结构。树枝节点可以包含树枝节点,也可以包含叶子节点,它其中有一个集合可以用于存储子节点,实现了在抽象根节点中定义的行为。在其业务方法中可以递归调用其子节点的业务方法。
优缺点

组合模式的优点主要有:

  • 简化客户端代码:组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象还是组合对象。
  • 增加新的构件方便:在组合体内加入新的对象很容易,客户端不会因为加入了新的对象而更改源代码。
  • 开闭原则:组合模式符合开闭原则,对扩展开放,对修改封闭。
  • 灵活的解决方案:为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合可以形成复杂的树形机构,但对树形结构的控制却很简单。

然而,组合模式也存在一些缺点:

  • 违反依赖倒置原则:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,这在一定程度上违反了依赖倒置原则。
  • 设计较复杂:客户端需要花更多时间理清类之间的层次关系。
  • 不容易限制容器中的构件:在组合模式中,不容易限制容器中可以包含的构件类型。

代码相关代码可以参考 代码仓库🌐

ps:本文原创,转载请注明出处


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IntelliJ IDEA 2024.1 更新亮点汇总:全面提升开发体验

IntelliJ IDEA 2024.1 更新亮点汇总&#xff1a;全面提升开发体验 文章目录 IntelliJ IDEA 2024.1 更新亮点汇总&#xff1a;全面提升开发体验摘要引言 IntelliJ IDEA 2024.1 的新增功能主要亮点全行代码完成 最终的支持 Java 22 功能新航站楼 贝塔编辑器中的粘滞线 人工智能助…

2024新版PHP在线客服系统多商户AI智能在线客服系统源码机器人自动回复即时通讯聊天系统源码PC+H5

搭建环境&#xff1a; 服务器 CPU 2核心 ↑ 运存 2G ↑ 宽带 5M ↑ 服务器操作系统 Linux Centos7.6-7.9 ↑ 运行环境&#xff1a; 宝塔面板 Nginx1.18- 1.22 PHP 7.1-7.3 MYSQL 5.6 -5.7 朵米客服系统是一款全功能的客户服务解决方案&#xff0c;提供多渠道支持…

深入浅出 -- 系统架构之负载均衡Nginx实现高可用

一、Nginx的高可用 线上如果采用单个节点的方式部署Nginx&#xff0c;难免会出现天灾人祸&#xff0c;比如系统异常、程序宕机、服务器断电、机房爆炸、地球毁灭....哈哈哈&#xff0c;夸张了。但实际生产环境中确实存在隐患问题&#xff0c;由于Nginx作为整个系统的网关层接入…

图解Java23种设计模式

好代码与烂代码 对代码质量的评判不能依据笼统的感觉&#xff0c;而是根据精准的标准去判断 我们应该从以下角度去判断自己写的代码到底是不是屎山&#xff1a; 可维护性&#xff08;Maintainability&#xff09;&#xff1a;能够以最小的成本和最快的速度修改或优化代码。可维…

git bash上传文件至github仓库

Linux运维工具-ywtool 目录 一.访问github二.新建仓库1.点击自己头像2.选择"your repositories"3.点击"New"4.创建新仓库 三.通过git bash软件上传文件1.提示2.打开git bash软件3.切换到本地仓库目录4.配置github的用户名和邮箱信息5.生成SSH Key6.github添…

麒麟系统ARM安装rabbitmq

简单记录下&#xff0c;信创服务器&#xff1a;麒麟系统&#xff0c;安装rabbitmq的踩坑记录。 本文章参考了很多大佬文章&#xff0c;我整理后提供。 一、安装基础依赖 yum -y install make gcc gcc-c kernel-devel m4 ncurses-devel openssl-devel unixODBC-devel 二、下载…

蓝桥杯刷题day14——盖印章【算法赛】

一、问题描述 小 Z 喜欢盖印章。 有一天,小 Z 得到了一个 nm 的网格图,与此同时,他的手上有两种印章(分别称为 A,B),如下图所示。 他想将这两种印章盖在这个网格图上。 由于小 Z 是一个有原则的人,他将按照以下规则进行操作。 每个印章所形成的图案的边必须和网格图…

性能分析-CPU知识

目录 CPU知识 cpu组成 查看cpu信息&#xff1a; top命令中 cpu相关&#xff1a; top命令看到系统负载&#xff1a; CPU负载 IO负载 上下文&#xff1a; CPU的寄存器和程序计数器----在cpu的控制器中 实战演示分析 top命令分析 arthas工具 进程上下文切换高的问题分析…

零信任安全模型:构建未来数字世界的安全基石

在数字化转型的浪潮中&#xff0c;云原生技术已成为推动企业创新和灵活性的关键力量&#x1f4a1;。然而&#xff0c;随着技术的进步和应用的广泛&#xff0c;网络安全威胁也日益严峻&#x1f513;&#xff0c;传统的网络安全模型已经难以应对复杂多变的网络环境。在这样的背景…

考研||考公||就业||其他?-------愿不再犹豫

大三下了&#xff0c;现在已经开学一个多月了&#xff0c;在上个学期的时候陆陆续续吧周围有的行动早的人已经开始准备考研了&#xff0c;当然这只是下小部分人吧&#xff0c;也有一部分人是寒假可能就开始了&#xff0c;更多的则是开学的时候&#xff0c;我的直观感受是图书馆…

Sundar Pichai 谈巨型公司创新挑战及他今年感到兴奋的事物

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

javaer 为什么称redis、rabbitmq这些东西为中间件?

中间件&#xff08;Middleware&#xff09;是位于客户端和服务器端之间的软件服务层&#xff0c;它提供了一种通用服务的方式&#xff0c;帮助不同的应用程序、系统组件和服务之间进行交互和数据交换。中间件隐藏了底层的复杂性&#xff0c;使得开发者可以专注于业务逻辑的实现…

珠海华发实业股份有限公司副总毛冰清莅临天府锋巢直播产业基地考察调研

3月19日&#xff0c;珠海华发实业股份有限公司副总毛冰清拜访天府锋巢直播产业基地&#xff08;以下简称天府锋巢&#xff09;&#xff0c;由产业招商总负责人姜国东进行接待。 基地建设情况 姜国东负责人介绍到&#xff0c;天府锋巢是由德商产投携手无锋科技于兴隆湖落地的成都…

循环双链表算法库构建

学习贺老师数据结构数据结构之自建算法库——循环双链表_数据结构编写一个程序linklist.cpp-CSDN博客 模仿单链表逻辑,实现双链表, 大差不差 v1.0: 实现基本功能 V1.0 1.主要功能: //(1)头插法建立循环双链表 void Create_Double_CyclicList_Head(DoubleLinkList_Cyclic *&am…

Redis常见的一些问题和注意事项

本文汇总的都是在我们公司出现过的常见问题以及自己曾经记录的注意事项。 我们公司sentinel模式以及RedisCluster集群两种部署方式都有使用&#xff0c;下面问题有些可能是哨兵模式下存在的&#xff0c;比如批量操作&#xff0c;下面可能不会特别说明。 1、注意热点key 之前单位…

YOLOV8 + 双目测距

YOLOV8 双目测距 1. 环境配置2. 测距流程和原理2.1 测距流程2.2 测距原理 3. 代码部分解析3.1 相机参数stereoconfig.py3.2 测距部分3.3 主代码yolov8-stereo.py 4. 实验结果4.1 测距4.2 测距跟踪4.3 测距跟踪分割4.4 视频展示 相关文章 1. YOLOv5双目测距&#xff08;python&…

MySQL高级篇(存储引擎InnoDB、MyISAM、Memory)

目录 1、存储引擎简介 1.1、查询建表语句&#xff0c;默认存储引擎&#xff1a;InnoDB 1.2、查看当前数据库支持的存储引擎 1.3、创建表&#xff0c;并指定存储引擎 2、 存储引擎-InnoDB介绍 2.1、存储引擎特点 3、MyISAM存储引擎 4、Memory存储引擎 5、InnoDB、MyISAM、Memory…

layui在上传多图时,allDone方法只是在第一次全部成功时调用了

问题点&#xff1a;在使用layui框架做多张图片上传时&#xff0c;遇见只有第一次操作上传图片时&#xff0c;触发了allDone全部上传成功的方法&#xff0c;后面再添加图片时&#xff0c;就不会调用这个方法 原因&#xff1a;是因为我删除了 choose 方法&#xff0c;并且也没有将…

算法部署 | 使用TensorRT+DeepSort+YOLOv5在NVIDIA-Jetson平台上部署目标跟踪算法

项目应用场景 面向英伟达 Jetson 边缘计算平台部署目标跟踪算法场景&#xff0c;使用深度学习算法 YOLOv5 DeepSort 来实现&#xff0c;并使用 TensorRT 进行算法加速&#xff0c;项目支持 NVIDIA Jetson Xavier、NVIDIA Jetson Xavier NX、X86 平台的算法部署。 项目效果 项…

uniapp - 微信小程序 - 使用uCharts的一些问题

文章目录 uniapp - 微信小程序 - 使用uCharts的一些问题一、开发者工具显示正常&#xff0c;真机调试统计图不随页面滚动二、数据过多开启滚动条&#xff0c;无法滑动滚动条三、饼图点击不显示提示窗/点击位置bug、多个同类型统计图点击不显示提示框问题四、 formatter 自定义 …