【设计模式——学习笔记】23种设计模式——中介者模式Observer(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录

  • 案例引入
    • 案例一
      • 普通实现
      • 中介者模式
    • 案例二
  • 介绍
    • 基础介绍
    • 登场角色
      • 尚硅谷
    • 《图解设计模式》
  • 案例实现
    • 案例一:智能家庭
      • 类图
      • 实现
    • 案例二:登录页面逻辑实现
      • 说明
      • 类图
      • 实现
  • 总结
  • 文章说明

案例引入

案例一

普通实现

在租房过程中,客户可能去找房东问房子是否可以租,但是房东可能要和家人进行一系列的沟通,最后还可能派出另一个家庭成员来和客户进行交流,整个沟通过程非常复杂、沟通线路繁多。如果是写成程序的模式,不同成员之间需要留好接口方便成员之间互相进行调用

在这里插入图片描述

【分析】

  • 各个成员彼此联系,你中有我,我中有你,不利于松耦合
  • 各个成员之间所传递的消息(参数)容易混乱
  • 当系统增加一个新的成员时,或者执行流程改变时,代码的可维护性、扩展性都不理想

【改进】

  • 使用中介者模式

中介者模式

客户只需要对接中介,其他成员互相之间不进行沟通,由中介来进行沟通。如 屋主—>爸爸 变成 屋主—>中介—>爸爸。通过中介的联络,可以将成员之间的关联关系都搞定
在这里插入图片描述

案例二

现在很多家庭都配备了智能家居,包括各种设备,如闹钟、咖啡机、电视机、窗帘……

当主人想要看电视时,会让多个设备协同工作,来自动完成看电视的准备工作,比如流程为: 闹铃响起->咖啡机开始做咖啡->窗帘自动落下->电视机开始播放

介绍

基础介绍

  • 在中介者模式中,团队组员之间不再互相沟通并私自做出决定,而是发生任何事情都向中介者报告,中介者站在整个团队的角度上对组员上报的事情做出决定。当中介者下达指示时,组员会立即执行
  • 用一个中介对象来封装一系列的对象交互方法。中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
  • 中介者模式属于行为型模式
  • 在MVC模式中,C(Controller控制器) 是M(Model模型) 和V(View视图)的中介者,在前后端交互时起到了中间人的作用

在这里插入图片描述

登场角色

尚硅谷

在这里插入图片描述

  • Mediator 就是抽象中介者,定义了同事对象到中介者对象的接口
  • Colleague 是抽象同事类
  • ConcreteMediator 具体的中介者对象,实现抽象方法,他需要知道所有的具体同事类,即以HashMap管理所有同事类,并接受某个同事对象的消息,来协调其他同事完成相应的任务
  • ConcreteColleague 具体的同事类,可能会有很多个,每个同事只知道自己的行为,而不了解其他同事类的行为(方法),他们都依赖中介者对象

《图解设计模式》

在这里插入图片描述

  • Mediator(仲裁者、中介者):负责定义与 Colleague 角色进行通信和做出决定的接口(API)
  • ConcreteMediator(具体的仲裁者、中介者):负责实现 Mediator 角色的接口(API),负责实际上如何做出决定
  • Colleague(同事):负责定义与Mediator角色进行通信的接口(API)
  • ConcreteColleague(具体的同事):负责实现 Colleague 角色的接口(API)

案例实现

案例一:智能家庭

类图

在这里插入图片描述

【操作流程】

  • 创建 ConcreteMediator 对象
  • 创建各个同事类对象,比如: Alarm、CoffeeMachine、TV
  • 在创建同事类对象的时候,就直接通过构造器,加入到 colleagueMap
  • 同事类对象,可以调用sendMessage,最终会去调用ConcreteMediator的getMessage方法
  • getMessage(核心方法)会根据接收到的同事对象发出的消息 来协调调用其它的同事对象来共同完成任务

实现

【抽象中介者类】

package com.atguigu.mediator.smarthouse;

public abstract class Mediator {
   /**
    * 将给中介者对象,加入到集合中
    * @param colleagueName
    * @param colleague
    */
   public abstract void register(String colleagueName, Colleague colleague);

   /**
    * 接收消息, 具体的同事对象发出
    * @param stateChange
    * @param colleagueName
    */
   public abstract void getMessage(int stateChange, String colleagueName);

   public abstract void sendMessage();
}

【具体中介者类】

package com.atguigu.mediator.smarthouse;

import java.util.HashMap;

/**
 * 具体的中介者类
 */
public class ConcreteMediator extends Mediator {
   /**
    * 集合,放入所有的同事对象
    */
   private HashMap<String, Colleague> colleagueMap;
   private HashMap<String, String> interMap;

   public ConcreteMediator() {
      colleagueMap = new HashMap<String, Colleague>();
      interMap = new HashMap<String, String>();
   }

   @Override
   public void register(String colleagueName, Colleague colleague) {
      colleagueMap.put(colleagueName, colleague);

      if (colleague instanceof Alarm) {
         interMap.put("Alarm", colleagueName);
      } else if (colleague instanceof CoffeeMachine) {
         interMap.put("CoffeeMachine", colleagueName);
      } else if (colleague instanceof TV) {
         interMap.put("TV", colleagueName);
      } else if (colleague instanceof Curtains) {
         interMap.put("Curtains", colleagueName);
      }

   }

   /**
    * 具体中介者的核心方法
    * 1. 根据得到消息,完成对应任务
    * 2. 中介者在这个方法,协调各个具体的同事对象,完成任务
    * @param stateChange
    * @param colleagueName
    */
   @Override
   public void getMessage(int stateChange, String colleagueName) {

      //处理闹钟发出的消息
      if (colleagueMap.get(colleagueName) instanceof Alarm) {
         if (stateChange == 0) {
            // 老司机做咖啡
            ((CoffeeMachine) (colleagueMap.get(interMap
                  .get("CoffeeMachine")))).StartCoffee();
            // 启动电视
            ((TV) (colleagueMap.get(interMap.get("TV")))).StartTv();
         } else if (stateChange == 1) {
            // 关掉电视
            ((TV) (colleagueMap.get(interMap.get("TV")))).StopTv();
         }

      } else if (colleagueMap.get(colleagueName) instanceof CoffeeMachine) {
         // 将窗帘升起来
         ((Curtains) (colleagueMap.get(interMap.get("Curtains"))))
               .UpCurtains();
      } else if (colleagueMap.get(colleagueName) instanceof TV) {
         //如果TV发现消息
      } else if (colleagueMap.get(colleagueName) instanceof Curtains) {
         //如果是以窗帘发出的消息,这里处理...
      }

   }

   @Override
   public void sendMessage() {

   }

}

【抽象同事类:Colleague】

package com.atguigu.mediator.smarthouse;

/**
 * 抽象同事类
 */
public abstract class Colleague {
   /**
    * 关联 Mediator
    */
   private Mediator mediator;
   public String name;

   public Colleague(Mediator mediator, String name) {
      this.mediator = mediator;
      this.name = name;
   }

   public Mediator GetMediator() {
      return this.mediator;
   }

   public abstract void SendMessage(int stateChange);
}

【具体同事类:闹钟】

package com.atguigu.mediator.smarthouse;

/**
 * 具体的同事类 闹钟
 */
public class Alarm extends Colleague {

   /**
    * 构造器
    * @param mediator
    * @param name
    */
   public Alarm(Mediator mediator, String name) {
      super(mediator, name);
      //在创建Alarm 同事对象时,将自己放入到ConcreteMediator 对象的集合中
      mediator.register(name, this);
   }

   public void SendAlarm(int stateChange) {
      SendMessage(stateChange);
   }

   @Override
   public void SendMessage(int stateChange) {
      //调用的中介者对象的getMessage
      this.GetMediator().getMessage(stateChange, this.name);
   }

}

【具体同事类:窗帘】

package com.atguigu.mediator.smarthouse;

/**
 * 窗帘
 */
public class Curtains extends Colleague {

   public Curtains(Mediator mediator, String name) {
      super(mediator, name);
      mediator.register(name, this);
   }

   @Override
   public void SendMessage(int stateChange) {
      this.GetMediator().getMessage(stateChange, this.name);
   }

   public void UpCurtains() {
      System.out.println("I am holding Up Curtains!");
   }

}

【具体同事类:电视】

package com.atguigu.mediator.smarthouse;

public class TV extends Colleague {

   public TV(Mediator mediator, String name) {
      super(mediator, name);
      mediator.register(name, this);
   }

   @Override
   public void SendMessage(int stateChange) {
      this.GetMediator().getMessage(stateChange, this.name);
   }

   public void StartTv() {
      System.out.println("It's time to StartTv!");
   }

   public void StopTv() {
      System.out.println("StopTv!");
   }
}

【主类】

package com.atguigu.mediator.smarthouse;

public class ClientTest {

   public static void main(String[] args) {
      //创建一个中介者对象
      Mediator mediator = new ConcreteMediator();

      //创建Alarm并且加入到 ConcreteMediator 对象的HashMap
      Alarm alarm = new Alarm(mediator, "alarm");

      //创建了CoffeeMachine对象,并且加入到 ConcreteMediator 对象的HashMap
      CoffeeMachine coffeeMachine = new CoffeeMachine(mediator,
            "coffeeMachine");

      //创建 Curtains, 并且加入到 ConcreteMediator 对象的HashMap
      Curtains curtains = new Curtains(mediator, "curtains");
      TV tV = new TV(mediator, "TV");

      //让闹钟发出消息
      alarm.SendAlarm(0);
      //做好咖啡
      coffeeMachine.FinishCoffee();
      alarm.SendAlarm(1);
   }

}

【运行】

It's time to startcoffee!
It's time to StartTv!
After 5 minutes!
Coffee is ok!
I am holding Up Curtains!
StopTv!

Process finished with exit code 0

【分析】

  • 程序拓展性较好:如果添加一个机器,只需要添加一个 ConcreteColleague 并修改 ConcreteMediator 的相关方法就行,客户端不用改变

案例二:登录页面逻辑实现

说明

在这里插入图片描述

需要实现一个系统登录表单功能,具体的处理逻辑如下:

  • 如果选择作为游客访问,那么禁用用户名输入框和密码输入框,使用户无法输入
  • 如果选择作为用户登录,那么启用用户名输入框和密码输入框,使用户可以输入
  • 如果在用户名输入框中一个字符都没有输入,那么禁用密码输入框,使用户无法输入密码
  • 如果在用户名输入框中输入了至少一个字符,那么启用密码输入框,使用户可以输入密码(当然,如果选择作为游客访问,那么密码框依然是禁用状态 )
  • 只有当用户名输入框和密码输入框中都至少输入一个字符后,OK 按钮才处于启用状态,可以被按下
  • 用户名输入框或密码输入框中一个字符都没有被输入的时候,禁用OK按钮,使其不可被按下(当然,如果选择作为游客访问,那么OK 按总是处于启用状态)
  • Cancel按钮总是处于启用状态,任何时候都可以按下该按钮

类图

在这里插入图片描述

实现

中介者接口和组员接口的方法并非固定就是这些,当中介者和组员需要其他合作的话,就需要定义更多的方法

【中介者接口】

package com.atguigu.mediator.Sample;

public interface Mediator {
    /**
     * 生成 Mediator 管理的组员
     */
    public abstract void createColleagues();

    /**
     * 每个组员都会调用这个方法来向中介者汇报
     */
    public abstract void colleagueChanged();
}

【组员接口】

package com.atguigu.mediator.Sample;

public interface Colleague {
    /**
     * 设置中介者,告诉组员中介者是谁
     *
     * @param mediator
     */
    public abstract void setMediator(Mediator mediator);

    /**
     * 告知组员中介者所下达的指令
     * @param enabled 控制是否启用组员的功能
     */
    public abstract void setColleagueEnabled(boolean enabled);
}

【组员:按钮】

package com.atguigu.mediator.Sample;

import java.awt.*;

public class ColleagueButton extends Button implements Colleague {
    private Mediator mediator;

    public ColleagueButton(String caption) {
        super(caption);
    }

    public void setMediator(Mediator mediator) {
        // 保存Mediator
        this.mediator = mediator;
    }

    public void setColleagueEnabled(boolean enabled) {
        // Mediator下达启用/禁用的指示
        // setEnabled是java.awt.Button定义的方法,用来控制按钮组件是启用还是禁用,当设置为false时,按钮无法被按下
        setEnabled(enabled);
    }
}

【组员:文本输入框】

package com.atguigu.mediator.Sample;

import java.awt.*;
import java.awt.event.TextEvent;
import java.awt.event.TextListener;

/**
 * 实现 TextListener 接口来实现监听事件
 */
public class ColleagueTextField extends TextField implements TextListener, Colleague {
    private Mediator mediator;

    public ColleagueTextField(String text, int columns) {   // 构造函数
        super(text, columns);
    }

    public void setMediator(Mediator mediator) {            // 保存Mediator
        this.mediator = mediator;
    }

    public void setColleagueEnabled(boolean enabled) {      // Mediator下达启用/禁用的指示
        setEnabled(enabled);
        // 控件启用时,背景色变成白色;否则变为灰色
        setBackground(enabled ? Color.white : Color.lightGray);
    }

    /**
     * TextListener 中定义的方法,监听文本内容的变化,并通知中介者
     * @param e
     */
    public void textValueChanged(TextEvent e) {
        // 当文字发生变化时通知Mediator
        mediator.colleagueChanged();
    }
}

【组员:单选按钮】

package com.atguigu.mediator.Sample;

import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

/**
 * 单选按钮
 */
public class ColleagueCheckbox extends Checkbox implements ItemListener, Colleague {
    private Mediator mediator;

    public ColleagueCheckbox(String caption, CheckboxGroup group, boolean state) {
        // 构造函数
        super(caption, group, state);
    }

    public void setMediator(Mediator mediator) {
        // 保存Mediator
        this.mediator = mediator;
    }

    public void setColleagueEnabled(boolean enabled) {
        // Mediator下达启用/禁用指示
        setEnabled(enabled);
    }

    /**
     * 监听单选按钮的状态变化
     * @param e
     */
    public void itemStateChanged(ItemEvent e) {
        // 当状态发生变化时通知Mediator
        mediator.colleagueChanged();
    }
}

【具体中介者】

package com.atguigu.mediator.Sample;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * 具体中介者
 */
public class LoginFrame extends Frame implements ActionListener, Mediator {
    private ColleagueCheckbox checkGuest;
    private ColleagueCheckbox checkLogin;
    private ColleagueTextField textUser;
    private ColleagueTextField textPass;
    private ColleagueButton buttonOk;
    private ColleagueButton buttonCancel;

    /**
     * 构造函数
     * 生成并配置各个Colleague后,显示对话框
     *
     * @param title
     */
    public LoginFrame(String title) {
        super(title);
        // 设置登录对话框的背景颜色
        setBackground(Color.lightGray);
        // 使用布局管理器生成4×2窗格
        setLayout(new GridLayout(4, 2));
        // 生成各个 Colleague
        createColleagues();
        // 配置 Colleague
        add(checkGuest);
        add(checkLogin);
        add(new Label("Username:"));
        add(textUser);
        add(new Label("Password:"));
        add(textPass);
        add(buttonOk);
        add(buttonCancel);
        // 设置初始的启用起用/禁用状态
        colleagueChanged();
        // 显示
        pack();
        show();
    }

    /**
     * 生成登录对话框所需要的各个Colleague
     */
    public void createColleagues() {
        // 生成
        CheckboxGroup g = new CheckboxGroup();
        checkGuest = new ColleagueCheckbox("Guest", g, true);
        checkLogin = new ColleagueCheckbox("Login", g, false);
        textUser = new ColleagueTextField("", 10);
        textPass = new ColleagueTextField("", 10);
        textPass.setEchoChar('*');
        buttonOk = new ColleagueButton("OK");
        buttonCancel = new ColleagueButton("Cancel");
        // 设置Mediator
        checkGuest.setMediator(this);
        checkLogin.setMediator(this);
        textUser.setMediator(this);
        textPass.setMediator(this);
        buttonOk.setMediator(this);
        buttonCancel.setMediator(this);
        // 设置Listener
        checkGuest.addItemListener(checkGuest);
        checkLogin.addItemListener(checkLogin);
        textUser.addTextListener(textUser);
        textPass.addTextListener(textPass);
        buttonOk.addActionListener(this);
        buttonCancel.addActionListener(this);
    }

    /**
     * 控制各个成员的状态
     * 接收来自于 Colleague 的通知,然后判断各 Colleague 的启用/禁用状态
     * 
     * 单选按钮的选中状态发生改变 或者 文本输入框的内容发生改变,都会调用这个方法
     */
    public void colleagueChanged() {
        // checkGuest.getState()获取游客模式的按钮是否处于选中状态
        if (checkGuest.getState()) {
            // 游客模式
            textUser.setColleagueEnabled(false);
            textPass.setColleagueEnabled(false);
            buttonOk.setColleagueEnabled(true);
        } else {
            // 登录模式
            textUser.setColleagueEnabled(true);
            userpassChanged();
        }
    }

    /**
     * 当textUser或是textPass文本输入框中的文字发生变化时
     * 判断各Colleage的启用/禁用状态
     */
    private void userpassChanged() {
        if (textUser.getText().length() > 0) {
            textPass.setColleagueEnabled(true);
            if (textPass.getText().length() > 0) {
                buttonOk.setColleagueEnabled(true);
            } else {
                buttonOk.setColleagueEnabled(false);
            }
        } else {
            textPass.setColleagueEnabled(false);
            buttonOk.setColleagueEnabled(false);
        }
    }

    public void actionPerformed(ActionEvent e) {
        System.out.println(e.toString());
        System.exit(0);
    }
}

【主类】

package com.atguigu.mediator.Sample;

public class Main {
    static public void main(String args[]) {
        new LoginFrame("Mediator Sample");
    }
}

【运行】

在这里插入图片描述

总结

【优点】

  • 多个类相互耦合,会形成网状结构(通信路线很多),使用中介者模式将网状结构分离为星型结构进行解耦
  • 减少类间依赖,峰低了耦合,符合迪米特原则
  • 如果出现了Bug,比较容易定位Bug的位置
  • ConcreteColleague容易复用(如果需要写一个新的对话框,那么按钮、文本输入框都可以很容易使用到新的对话框中)

【缺点】

  • 中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
  • 如果设计不当,中介者对象本身变得过于复杂,这点在实际使用时,要特别注意
  • ConcreteMediator难以复用,因为其依赖于特定的应用程序

文章说明

  • 本文章为本人学习尚硅谷的学习笔记,文章中大部分内容来源于尚硅谷视频(点击学习尚硅谷相关课程),也有部分内容来自于自己的思考,发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识,如有侵权请联系删除,最后对尚硅谷的优质课程表示感谢。
  • 本人还同步阅读《图解设计模式》书籍(图解设计模式/(日)结城浩著;杨文轩译–北京:人民邮电出版社,2017.1),进而综合两者的内容,让知识点更加全面

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

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

相关文章

2.5D游戏是如何做出来的呢,2.5D游戏快速制作教程

前言 【Unity实战篇 】 | 如何制作一款2.5D游戏&#xff0c;2.5D游戏制作案例一、2.5D 游戏概念二、绘制地图三、添加玩家动画和移动等操作四、视角配置4.1 调整摄像机与场景对象的角度4.2 增加镜头旋转功能 五、游戏效果展示 总结 前言 玩过游戏的朋友都知道&#xff0c;市面…

HarmonyOS NEXT,生命之树初长成

在不同的神话体系中&#xff0c;都有着关于生命之树的记载。 比如在北欧神话中&#xff0c;一株巨大的树木联结着九大世界&#xff0c;其被称为“尤克特拉希尔”Yggdrasill。在中国的《山海经》中&#xff0c;也有着“建木”的传说&#xff0c;它“有九欘&#xff0c;下有九枸&…

idea添加翻译插件并配置有道翻译

1、安装Translation插件 2、 创建有道云应用 有道智云控制台 3、设置idea 4、效果&#xff08;选中文本右键翻译&#xff0c;默认快捷键CtrlShiftY&#xff09;

安达发制造工业迈向智能化:APS高级计划排程助力提升生产效率

随着市场竞争的加剧&#xff0c;制造企业纷纷寻求提高生产效率和降低成本的方法。近年来&#xff0c;越来越多的制造企业开始采用APS(高级计划与排程)系统&#xff0c;以优化生产计划和排程&#xff0c;提高生产效率&#xff0c;并在竞争中取得优势。 现代制造业通常面临复杂的…

Idea中maven无法下载源码

今天在解决问题的时候想要下载源码&#xff0c;突然发现idea无法下载&#xff0c;这是真的蛋疼&#xff0c;没办法查看原因&#xff0c;最后发现问题的原因居然是因为Maven&#xff0c;由于我使用的idea的内置的Bundle3的Maven&#xff0c;之前没有研究过本地安装和内置的区别&…

ESP 32 蓝牙虚拟键盘链接笔记本电脑的键值问题

由于打算利用esp32 通过蓝牙链接电脑后实现一些特俗的键盘功能&#xff0c;所以就折腾了一下&#xff0c;折腾最耗费时间的却是键值问题&#xff0c;让一个20多年的老司机重新补充了知识 过程曲折就不说了&#xff0c;直接说结果。 我们通过网络搜索获取的键值和蓝牙模拟键盘传…

Leetcode-每日一题【剑指 Offer 11. 旋转数组的最小数字】

题目 把一个数组最开始的若干个元素搬到数组的末尾&#xff0c;我们称之为数组的旋转。 给你一个可能存在 重复 元素值的数组 numbers &#xff0c;它原来是一个升序排列的数组&#xff0c;并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如&#xff0c;数组 [3,4…

【论文阅读】对抗溯源图主机入侵检测系统的模仿攻击(NDSS-2023)

作者&#xff1a;伊利诺伊大学芝加哥分校-Akul Goyal、Gang Wang、Adam Bates&#xff1b;维克森林大学-Xueyuan Han、 引用&#xff1a;Goyal A, Han X, Wang G, et al. Sometimes, You Aren’t What You Do: Mimicry Attacks against Provenance Graph Host Intrusion Detect…

docker容器监控:Cadvisor +Prometheus+Grafana的安装部署

目录 Cadvisor PrometheusGrafana的安装部署 一、安装docker&#xff1a; 1、安装docker-ce 2、阿里云镜像加速器 3、下载组件镜像 4、创建自定义网络 二、部署Cadvisor 1、被监控主机上部署Cadvisor容器 2、访问cAdvisor页面 三、安装prometheus 1、部署Prometheus…

20230806将ASF格式的视频转换为MP4

20230806将ASF格式的视频转换为MP4 2023/8/6 18:47 缘起&#xff0c;自考中山大学的《计算机网络》&#xff0c;考试《数据库系统原理》的时候找到视频&#xff0c;由于个人的原因&#xff0c;使用字幕更加有学习效率&#xff01; 由于【重型】的PR2023占用资源较多&#xff0c…

Spring security之JWT

JWT 这里写目录标题 JWT一级目录二级目录三级目录1.什么是JWT 2.JWT的组成部分3.编码/解码4.特点5. 为什么使用JWT5.1传统的验证方式 5.2基于JWT的验证方式6.JWT进行登录验证6.1依赖安装6.2编写UserDetailServiceImpl类6.3编写UserDetailsImpl类6.4 实现config.SecurityConfig类…

算法与数据结构(二十二)动态规划解题套路框架

动态规划解题套路框架 此文只在个人总结 labuladong 动态规划框架&#xff0c;仅限于学习交流&#xff0c;版权归原作者所有&#xff1b; 动态规划问题&#xff08;Dynamic Programming&#xff09;应该是很多读者头疼的&#xff0c;不过这类问题也是最具有技巧性&#xff0c…

替换开源LDAP,某科技企业用宁盾目录统一身份,为业务敏捷提供支撑

客户介绍 某高科技企业成立于2015年&#xff0c;是一家深耕于大物流领域的人工智能公司&#xff0c;迄今为止已为全球16个国家和地区&#xff0c;120余家客户打造智能化升级体验&#xff0c;场景覆盖海陆空铁、工厂等货运物流领域。 该公司使用开源LDAP面临的挑战 挑战1 开源…

【用于全变分去噪的分裂布雷格曼方法】实施拆分布雷格曼方法进行总变异去噪研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

docker菜谱

DockerHub&#xff1a;https://hub.docker.com/ 记录docker常用软件安装&#xff0c;欢迎大家来投稿。&#x1f60e;&#x1f60e;&#x1f60e; 文章目录 1. Redis2. MariaDB 1. Redis dockerhub:https://hub.docker.com/_/redis 1、下载redis镜像&#xff1a; docker pull r…

【MFC】05.MFC第一大机制:程序启动机制-笔记

MFC程序开发所谓是非常简单&#xff0c;但是对于我们逆向人员来说&#xff0c;如果想要逆向MFC程序&#xff0c;那么我们就必须了解它背后的机制&#xff0c;这样我们才能够清晰地逆向出MFC程序&#xff0c;今天这篇文章就来带领大家了解MFC的第一大机制&#xff1a;程序启动机…

echarts 图表饼状图 实例

效果图&#xff1a; 代码&#xff1a; draw(data1, data2) {var option {// backgroundColor: rgb(10,36,68),color: [#F19611 ,#0095FE,#162D86,#0096FF,#05F8FF,#FFD985,#FACDAA,#F4A49E,#EE7B91,#E85285,#BE408C,#942D93,#171E6D,#1E3388,#27539B,#3073AE,#3993C2,#42B3D…

JVM如何调优

一、JVM内存模型及垃圾收集算法 1.根据Java虚拟机规范&#xff0c;JVM将内存划分为&#xff1a; New&#xff08;年轻代&#xff09; Tenured&#xff08;年老代&#xff09; 永久代&#xff08;Perm&#xff09; 其中New和Tenured属于堆内存&#xff0c;堆内存会从JVM启动参…

day0808

1.单链表实现约瑟夫环 #include "joseph.h" LoopLink list_create(int m) {LoopLink L (LoopLink)malloc(sizeof(Node));if(NULLL){printf("内存创建失败\n");return 0;}LoopLink qL;for(int i1; i<m; i){LoopLink p (LoopLink)malloc(sizeof(Node));…

MyBatis-XML映射文件

XML映射文件 规范 XML映射文件的名称与Mapper接口名称一致&#xff08;EmpMapper对应EmpMpper.xml&#xff09;&#xff0c;并且将XML映射文件和Mapper接口放置在相同包下&#xff08;同包同名&#xff09; ​​​ 在maven项目结构中所有的配置文件都在resources目录之下&…