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

news2024/11/13 15:07:10

案例引入

  • 有一套智能家电,其中有照明灯、风扇、冰箱、洗衣机,这些智能家电来自不同的厂家,我们不想针对每一种家电都安装一个手机App来分别控制,希望只要一个app就可以控制全部智能家电
  • 要实现一个app控制所有智能家电的需要,则每个智能家电厂家都要提供一个统一的接口给app调用,这样可以考虑使用命令模式
  • 命令模式可将“动作的请求者”从“动作的执行者”对象中解耦出来
  • 在我们的例子中,动作的请求者是手机app,动作的执行者是每个厂商的一个家电产品

介绍

基础介绍

  • 一个类在进行工作时会调用自己或是其他类的方法,虽然调用结果会反映在对象的状态中,但并不会留下工作的历史记录。这时,如果有一个类用来表示“请示进行这项工作”的“命令”就会方便很多。每一项想做的工作就不再是“方法的调用”这种动态处理了,而是一个表示命令的类的实例,即可以用“物”来表示。要想管理工作的历史记录,只需管理这些实例的集合即可,而且还可以随时再次执行过去的命令,或是将多个过去的命令整合为一个新命令并执行。这样的模式称为命令模式
  • 命令模式使得请求发送者请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦,我们只需在程序运行时指定具体的请求接收者即可
  • 在命令模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命令),同时命令模式也支持可撤销的操作
  • 通俗易懂的理解:将军发布命令,士兵去执行(将军只需要发布一个进攻命令即可,不需要指定哪位士兵要做什么,士兵就会各司其职)。其中有几个角色:将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将军和士兵)

登场角色

  • Command(命令):负责定义命令的接口(API)
  • ConcreteCommand(具体的命令):ConcreteCommand角色负责实现在Command角色中定义的接口(API)。聚合接收者,将一个接收者对象与一个动作绑定,调用接收者相应的操作来实现execute
  • Receiver(接收者):Receiver角色是执行命令的对象,知道如何实施和执行一个请求对应的操作
  • Client(请求者):Client角色负责生成ConcreteCommand角色并分配Receiver角色
  • Invoker(发动者):调用在Command 角色中定义的接口(API)

在这里插入图片描述

案例实现

案例一

在这里插入图片描述

实现

【Commond】

package com.atguigu.command;

/**
 * 创建命令接口
 */
public interface Command {

    /**
     * 执行动作(操作)
     */
    public void execute();

    /**
     * 撤销动作(操作)
     */
    public void undo();
}

【电灯命令执行者】

package com.atguigu.command;

/**
 * 真正执行者
 */
public class LightReceiver {

   public void on() {
      System.out.println(" 电灯打开了.. ");
   }

   public void off() {
      System.out.println(" 电灯关闭了.. ");
   }
}

【关灯命令】

package com.atguigu.command;

public class LightOffCommand implements Command {

   /**
    * 聚合LightReceiver
    */
   LightReceiver light;

   /**
    * 构造器
    * @param light
    */
   public LightOffCommand(LightReceiver light) {
      super();
      this.light = light;
   }

   @Override
   public void execute() {
      // 调用接收者的方法
      light.off();
   }

   @Override
   public void undo() {
      // 调用接收者的方法
      light.on();
   }
}

【开灯命令】

package com.atguigu.command;

public class LightOnCommand implements Command {

    /**
     * 聚合LightReceiver
     */
    LightReceiver light;

    /**
     * 构造器
     *
     * @param light
     */
    public LightOnCommand(LightReceiver light) {
        super();
        this.light = light;
    }

    @Override
    public void execute() {
        //调用接收者的方法
        light.on();
    }

    @Override
    public void undo() {
        //调用接收者的方法
        light.off();
    }

}

【电视命令执行者】

package com.atguigu.command;

public class TVReceiver {

   public void on() {
      System.out.println(" 电视机打开了.. ");
   }

   public void off() {
      System.out.println(" 电视机关闭了.. ");
   }
}

【关电视命令】

package com.atguigu.command;

public class TVOffCommand implements Command {

    /**
     * 聚合TVReceiver
     */
    TVReceiver tv;

    /**
     * 构造器
     *
     * @param tv
     */
    public TVOffCommand(TVReceiver tv) {
        super();
        this.tv = tv;
    }

    @Override
    public void execute() {
        // 调用接收者的方法
        tv.off();
    }

    @Override
    public void undo() {
        // 调用接收者的方法
        tv.on();
    }
}

【开电视命令】

package com.atguigu.command;

public class TVOnCommand implements Command {

    /**
     * 聚合TVReceiver
     */
    TVReceiver tv;

    /**
     * 构造器
     *
     * @param tv
     */
    public TVOnCommand(TVReceiver tv) {
        super();
        this.tv = tv;
    }

    @Override
    public void execute() {
        // 调用接收者的方法
        tv.on();
    }

    @Override
    public void undo() {
        // 调用接收者的方法
        tv.off();
    }
}

【空命令】

package com.atguigu.command;

/**
 * 没有任何命令,即空执行: 用于初始化每个按钮, 当调用空命令时,对象什么都不做
 * 其实,这样是一种设计模式, 可以省掉对空判断
 * @author Administrator
 *
 */
public class NoCommand implements Command {

   @Override
   public void execute() {

   }

   @Override
   public void undo() {

   }

} 

【遥控器】

package com.atguigu.command;

public class RemoteController {

    /**
     * 开 按钮的命令数组
     */
    Command[] onCommands;
    Command[] offCommands;

    /**
     * 执行撤销的命令,必须要记住上一次执行的命令对应的撤销命令才能撤销
     */
    Command undoCommand;

    /**
     * 构造器,完成对按钮初始化
     */
    public RemoteController() {
        onCommands = new Command[5];
        offCommands = new Command[5];

        // 初始化五组命令,初始化为空命令
        for (int i = 0; i < 5; i++) {
            onCommands[i] = new NoCommand();
            offCommands[i] = new NoCommand();
        }
    }

    /**
     * 给我们的按钮设置你需要的命令
     *
     * @param no 命令编号
     * @param onCommand
     * @param offCommand
     */
    public void setCommand(int no, Command onCommand, Command offCommand) {
        onCommands[no] = onCommand;
        offCommands[no] = offCommand;
    }

    /**
     * 按下开按钮
     *
     * @param no
     */
    public void onButtonWasPushed(int no) {
        // 找到你按下的开的按钮, 并调用对应方法
        onCommands[no].execute();
        // 记录这次的操作,用于撤销
        undoCommand = onCommands[no];
    }

    /**
     * 按下开按钮
     *
     * @param no
     */
    public void offButtonWasPushed(int no) {
        // 找到你按下的关的按钮, 并调用对应方法
        offCommands[no].execute();
        // 记录这次的操作,用于撤销
        undoCommand = offCommands[no];
    }

    /**
     * 按下撤销按钮
     */
    public void undoButtonWasPushed() {
        undoCommand.undo();
    }

}

【客户端】

package com.atguigu.command;

public class Client {

   public static void main(String[] args) {

      //使用命令设计模式,完成通过遥控器,对电灯的操作

      //创建电灯的对象(接受者)
      LightReceiver lightReceiver = new LightReceiver();

      //创建电灯相关的开关命令
      LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
      LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);

      //需要一个遥控器
      RemoteController remoteController = new RemoteController();

      //给我们的遥控器设置命令, 比如 no = 0 是电灯的开和关的操作
      remoteController.setCommand(0, lightOnCommand, lightOffCommand);

      System.out.println("--------按下灯的开按钮-----------");
      remoteController.onButtonWasPushed(0);
      System.out.println("--------按下灯的关按钮-----------");
      remoteController.offButtonWasPushed(0);
      System.out.println("--------按下撤销按钮-----------");
      remoteController.undoButtonWasPushed();


      System.out.println("=========使用遥控器操作电视机==========");

      TVReceiver tvReceiver = new TVReceiver();

      TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver);
      TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver);

      //给我们的遥控器设置命令, 比如 no = 1 是电视机的开和关的操作
      remoteController.setCommand(1, tvOnCommand, tvOffCommand);

      System.out.println("--------按下电视机的开按钮-----------");
      remoteController.onButtonWasPushed(1);
      System.out.println("--------按下电视机的关按钮-----------");
      remoteController.offButtonWasPushed(1);
      System.out.println("--------按下撤销按钮-----------");
      remoteController.undoButtonWasPushed();

   }

}

【运行】

--------按下灯的开按钮-----------
 电灯打开了.. 
--------按下灯的关按钮-----------
 电灯关闭了.. 
--------按下撤销按钮-----------
 电灯打开了.. 
=========使用遥控器操作电视机==========
--------按下电视机的开按钮-----------
 电视机打开了.. 
--------按下电视机的关按钮-----------
 电视机关闭了.. 
--------按下撤销按钮-----------
 电视机打开了.. 

Process finished with exit code 0

案例二

介绍

这段示例程序是一个画图软件,它的功能很简单,即用户拖动鼠标时程序会绘制出红色圆点,点击 clear 按钮后会清除所有的圆点。

在这里插入图片描述

实现

在这里插入图片描述

【命令接口】

package com.atguigu.command.Sample.command;

public interface Command {
    /**
     * 执行
     */
    public abstract void execute();
}

【历史命令集:由多条命令整合成的命令】

如果保存这个实例,就可以永久保存历史数据

package com.atguigu.command.Sample.command;

import java.util.Iterator;
import java.util.Stack;

/**
 * 由多条命令整合成的命令
 */
public class MacroCommand implements Command {
    /**
     * 存储命令的栈
     */
    private Stack commands = new Stack();

    /**
     * 执行
     */
    public void execute() {
        // 一次性执行一系列命令
        Iterator it = commands.iterator();
        while (it.hasNext()) {
            ((Command) it.next()).execute();
        }
    }

    /**
     * 添加命令
     *
     * @param cmd
     */
    public void append(Command cmd) {
        if (cmd != this) {
            // 判断不是自己再添加进去,不然会死循环
            commands.push(cmd);
        }
    }

    /**
     * 删除最后一条命令
     */
    public void undo() {
        if (!commands.empty()) {
            // 取出最后添加到栈的命令
            commands.pop();
        }
    }

    /**
     * 删除所有命令
     */
    public void clear() {
        commands.clear();
    }
}

【绘制点命令】

package com.atguigu.command.Sample.drawer;


import com.atguigu.command.Sample.command.Command;
import java.awt.*;

public class DrawCommand implements Command {

    /**
     * 绘制对象
     */
    protected Drawable drawable;

    /**
     * 绘制位置 Point 是 java.awt 包的类,含有 (x,y) 坐标
     */
    private Point position;

    /**
     * 构造函数
     *
     * @param drawable
     * @param position
     */
    public DrawCommand(Drawable drawable, Point position) {
        this.drawable = drawable;
        this.position = position;
    }

    /**
     * 执行
     */
    public void execute() {
        drawable.draw(position.x, position.y);
    }
}

【绘制对象接口】

package com.atguigu.command.Sample.drawer;

public interface Drawable {
    public abstract void draw(int x, int y);
}

【绘图类】

package com.atguigu.command.Sample.drawer;

import com.atguigu.command.Sample.command.MacroCommand;

import java.awt.*;

/**
 * 继承Canvas
 */
public class DrawCanvas extends Canvas implements Drawable {
    /**
     * 颜色
     */
    private Color color = Color.red;
    /**
     * 要绘制的圆点的半径
     */
    private int radius = 6;
    /**
     * 命令的历史记录
     */
    private MacroCommand history;

    /**
     * 构造函数
     *
     * @param width
     * @param height
     * @param history
     */
    public DrawCanvas(int width, int height, MacroCommand history) {
        // 设置画布尺寸
        setSize(width, height);
        // 设置画布颜色
        setBackground(Color.white);
        this.history = history;
    }

    /**
     * 重新全部绘制
     * @param g   the specified Graphics context
     */
    public void paint(Graphics g) {
        history.execute();
    }

    /**
     * 绘制
     * @param x
     * @param y
     */
    public void draw(int x, int y) {
        Graphics g = getGraphics();
        // 设置笔画颜色
        g.setColor(color);
        // 绘制圆点
        g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
    }
}

【主类】

package com.atguigu.command.Sample;

import com.atguigu.command.Sample.command.*;
import com.atguigu.command.Sample.drawer.*;

import javax.swing.*;
import java.awt.event.*;

public class Main extends JFrame implements ActionListener, MouseMotionListener, WindowListener {
    /**
     * 存储绘制的历史记录
     */
    private MacroCommand history = new MacroCommand();
    /**
     * 绘制区域
     */
    private DrawCanvas canvas = new DrawCanvas(400, 400, history);
    /**
     * 创建删除按钮
     */
    private JButton clearButton  = new JButton("clear");

    /**
     * 构造函数
     * @param title
     */
    public Main(String title) {
        super(title);

        this.addWindowListener(this);
        // 添加鼠标移动事件
        canvas.addMouseMotionListener(this);
        // 添加鼠标点击事件
        clearButton.addActionListener(this);

        /// 创建布局
        // 创建横向的盒子来存放按钮
        Box buttonBox = new Box(BoxLayout.X_AXIS);
        buttonBox.add(clearButton);
        // 创建纵向的盒子来存放按钮盒子和画布
        Box mainBox = new Box(BoxLayout.Y_AXIS);
        mainBox.add(buttonBox);
        mainBox.add(canvas);
        getContentPane().add(mainBox);

        pack();
        show();
    }

    /**
     * ActionListener接口中的方法
     * @param e
     */
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == clearButton) {
            // 清空历史命令
            history.clear();
            // 清空画布
            canvas.repaint();
        }
    }

    public void mouseMoved(MouseEvent e) {
    }

    /**
     *  MouseMotionListener接口中的方法
     * @param e
     */
    public void mouseDragged(MouseEvent e) {
        // 鼠标位置一改变,就创建绘制点命令放到命令集合中
        Command cmd = new DrawCommand(canvas, e.getPoint());
        // 执行绘制
        cmd.execute();
        history.append(cmd);
    }

    /**
     *  WindowListener接口中的方法
     * @param e
     */
    public void windowClosing(WindowEvent e) {
        System.exit(0);
    }
    public void windowActivated(WindowEvent e) {}
    public void windowClosed(WindowEvent e) {}
    public void windowDeactivated(WindowEvent e) {}
    public void windowDeiconified(WindowEvent e) {}
    public void windowIconified(WindowEvent e) {}
    public void windowOpened(WindowEvent e) {}

    public static void main(String[] args) {
        new Main("Command Pattern Sample");
    }
}

在这里插入图片描述

【运行】

在这里插入图片描述

拓展

如何示例程序中增加“设置颜色”的功能。

【颜色命令】

package com.atguigu.command.A1.drawer;


import com.atguigu.command.A1.command.Command;

import java.awt.*;

public class ColorCommand implements Command {
    /**
     * 绘制对象
     */
    protected Drawable drawable;
    /**
     * 颜色
     */
    private Color color;

    /**
     * 构造函数
     *
     * @param drawable
     * @param color
     */
    public ColorCommand(Drawable drawable, Color color) {
        this.drawable = drawable;
        this.color = color;
    }

    /**
     * 执行
     * 设置画笔的颜色
     */
    public void execute() {
        drawable.setColor(color);
    }
}

【主类】

package com.atguigu.command.A1;


import com.atguigu.command.A1.command.Command;
import com.atguigu.command.A1.command.MacroCommand;
import com.atguigu.command.A1.drawer.ColorCommand;
import com.atguigu.command.A1.drawer.DrawCanvas;
import com.atguigu.command.A1.drawer.DrawCommand;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Main extends JFrame implements ActionListener, MouseMotionListener, WindowListener {
    private MacroCommand history = new MacroCommand();
    private DrawCanvas canvas = new DrawCanvas(400, 400, history);
    private JButton clearButton = new JButton("clear");
    /**
     * 红色按钮
     */
    private JButton redButton = new JButton("red");
    /**
     * 绿色按钮
     */
    private JButton greenButton = new JButton("green");
    /**
     * 蓝色按钮
     */
    private JButton blueButton = new JButton("blue");

    /**
     * 构造函数
     *
     * @param title
     */
    public Main(String title) {
        super(title);

        this.addWindowListener(this);
        canvas.addMouseMotionListener(this);
        clearButton.addActionListener(this);
        redButton.addActionListener(this);
        greenButton.addActionListener(this);
        blueButton.addActionListener(this);

        Box buttonBox = new Box(BoxLayout.X_AXIS);
        buttonBox.add(clearButton);
        buttonBox.add(redButton);
        buttonBox.add(greenButton);
        buttonBox.add(blueButton);
        Box mainBox = new Box(BoxLayout.Y_AXIS);
        mainBox.add(buttonBox);
        mainBox.add(canvas);
        getContentPane().add(mainBox);

        pack();
        show();
    }

    /**
     * ActionListener接口中的方法
     * 点击不同颜色的按钮,设置不同颜色画笔
     *
     * @param e
     */
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == clearButton) {
            history.clear();
            canvas.init();
            canvas.repaint();
        } else if (e.getSource() == redButton) {
            Command cmd = new ColorCommand(canvas, Color.red);
            history.append(cmd);
            cmd.execute();
        } else if (e.getSource() == greenButton) {
            Command cmd = new ColorCommand(canvas, Color.green);
            history.append(cmd);
            cmd.execute();
        } else if (e.getSource() == blueButton) {
            Command cmd = new ColorCommand(canvas, Color.blue);
            history.append(cmd);
            cmd.execute();
        }
    }

    /**
     * MouseMotionListener接口中的方法
     *
     * @param e
     */
    public void mouseMoved(MouseEvent e) {
    }

    public void mouseDragged(MouseEvent e) {
        Command cmd = new DrawCommand(canvas, e.getPoint());
        history.append(cmd);
        cmd.execute();
    }

    /**
     * WindowListener接口中的方法
     *
     * @param e
     */
    public void windowClosing(WindowEvent e) {
        System.exit(0);
    }

    public void windowActivated(WindowEvent e) {
    }

    public void windowClosed(WindowEvent e) {
    }

    public void windowDeactivated(WindowEvent e) {
    }

    public void windowDeiconified(WindowEvent e) {
    }

    public void windowIconified(WindowEvent e) {
    }

    public void windowOpened(WindowEvent e) {
    }

    public static void main(String[] args) {
        new Main("Command Pattern Sample");
    }
}

【运行】

在这里插入图片描述

命令模式在JdbcTemplate源码中的应用

应用模式和标准的命令模式有点区别,但是精髓是差不多的

在这里插入图片描述

在这里插入图片描述

还有其他的命令执行者

在这里插入图片描述

在这里插入图片描述

总结

【优点】

  • 发起请求的对象执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象的execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何实现的。命令对象(就是具体的命令)会负责让接收者执行调用者请求的动作,也就是说:”请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用
  • 命令模式容易设计一个命令队列。只要把命令对象放到队列,就可以多线程地执行命令。不仅如此,还容易将命令执行的历史纪录保存起来
  • 命令模式容易实现对请求的撤销和重做
  • 空命令也是一种设计模式,它为我们省去了判空的操作。在上面的实例中,如果没有用空命令,我们每按下一个按键都要判空,这给我们编码带来一定的麻烦(声明命令数组时,首先将数组的元素全部初始化为空命令)

【缺点】

  • 可能导致某些系统有过多的具体命令类,增加了系统的复杂度

文章说明

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

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

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

相关文章

小程序开发趋势:探索人工智能在小程序中的应用

第一章&#xff1a;引言 小程序开发近年来取得了快速的发展&#xff0c;成为了移动应用开发的重要一环。随着人工智能技术的飞速发展&#xff0c;越来越多的企业开始探索如何将人工智能应用于小程序开发中&#xff0c;为用户提供更智能、便捷的服务。本文将带您一起探索人工智能…

YOLOv8+DeepSORT多目标跟踪(行人车辆计数与越界识别)视频教程

课程链接&#xff1a;https://edu.csdn.net/course/detail/38870 本课程使用YOLOv8和DeepSORT对视频中的行人、车辆做多目标跟踪计数与越界识别&#xff0c;开展YOLOv8目标检测和DeepSORT多目标跟踪强强联手的应用。 课程分别在Windows和Ubuntu系统上做项目演示&#xff0c;并…

基于SpringBoot+Vue的在线考试系统设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

【样式】默认都不选

html <view class"u-flex u-m-t-32 u-m-b-24 u-f-s-24"><view class"u-flex" click"navFun(1)"><text>佣金率</text><image src"/static/img/pai1.png" mode"" class"u-w-28 u-h-32"…

RabbitMQ 教程 | 第7章 RabbitMQ 运维

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

P7883 平面最近点对(加强加强版)

题目 思路 一眼二分&#xff0c;把平面分成两部分&#xff0c;查左右两边&#xff0c;但是还有可能跨中间的线&#xff0c;所以这个也得判 代码 #include<bits/stdc.h> using namespace std; #define int long long const int maxn4e510; pair<int,int> a[maxn]…

Java版Spring Cloud+Spring Boot+Mybatis+uniapp知识付费平台讲解+免费搭建 qt

&#xfeff;Java版知识付费源码 Spring CloudSpring BootMybatisuniapp前后端分离实现知识付费平台 提供职业教育、企业培训、知识付费系统搭建服务。系统功能包含&#xff1a;录播课、直播课、题库、营销、公司组织架构、员工入职培训等。 提供私有化部署&#xff0c;免费售…

亚马逊云科技HPC解决方案,帮助浙江大学实现成本和科研任务的双丰收

浙江大学土壤学科是朱祖祥院士等几代土壤科学家共同创建的A国家重点学科&#xff0c;整体实力雄厚&#xff0c;优势特色明显&#xff0c;总体水平居国内前列。在亚马逊云科技科研创新支持计划&#xff08;Amazon Web Services Cloud Credits for Research&#xff09;的多次支持…

发掘JavaScript潜力:掌握高级技巧,成为JavaScript编程大师!

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! &#x1f4da; 前言 众所周知&#xff0c;JavaScript 是一种非常流行&#x1f525;的编程语言&#xff0c;它已经成为了网…

3000字详解:风控核心岗位及核心价值

01、信贷场景中所谓风控是什么&#xff1f; 从一个小故事说起&#xff1a; “风控是什么&#xff1f;” “你走过大桥么&#xff1f;” “桥上有栏杆么&#xff1f;” “有” “你过桥时会扶栏杆么” “一般不扶” “那栏杆是不是没必要有呢” “那还是得有啊&#xf…

SpringBoot统一功能处理(AOP思想实现)(统一用户登录权限验证 / 异常处理 / 数据格式返回)

主要是三个处理&#xff1a; 1、统一用户登录权限验证&#xff1b; 2、统一异常处理&#xff1b; 3、统一数据格式返回。 目录 一、用户登录权限校验 &#x1f345; 1、使用拦截器 &#x1f388; 1.1自定义拦截器 &#x1f388; 1.2 设置自定义拦截器 &#x1f388;创建cont…

vue3中使用原始标签制作一个拖拽和点击上传组件上传成功后展示

在Vue3中&#xff0c;可以使用<input type"file">标签来实现上传文件的功能&#xff0c;同时可以通过<div>标签来实现拖拽上传的功能。 首先&#xff0c;在template中定义一个包含<input>和<div>标签的组件&#xff1a; <template>&…

使用Vscode编辑keil工程

一、需要安装的插件 1. Keil Assistant 2. C/C 3. 中文配置&#xff1a; 二、插件配置 1. Keil Assistant 添加Keil的安装路径 接下来就可以使用vscode编辑Keil的工程了&#xff0c;调试编译和下载程序需要返回到Keil中进行操作。 三、Vscode常用快捷键 可以自定义进行配置…

【Unity实用插件篇】| 学会使用 可编程瓦片Tile Map,快速搭建2D地图

前言【Unity 实用插件篇】| 学会使用 可编程瓦片Tile Map,快速搭建2D地图一、导入 Tile Map Editor二、创建调色板 Tile Palette三、快速绘制地图四、TilePalette 调色板功能介绍五、TileMap 相关组件属性介绍GirdTilemapTilemap Renderer 瓦片地图渲染器Tile Assets 瓦片资源…

如何创建百度百科词条?教你如何在百度百科上创建个人专业词条

百度百科是一个拥有海量内容的知识库&#xff0c;每天有数百万人访问该网站以获取有用的信息和知识。如果您是一家企业、一位专业人士或学者&#xff0c;那么在百度百科上创建一个词条是一个很好的品牌推广或个人形象塑造的机会。在本文中&#xff0c;一秒推小编将讲述如何创建…

安防视频综合管理合平台EasyCVR可支持的视频播放协议有哪些?

EasyDarwin开源流媒体视频EasyCVR安防监控平台可提供视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、云台控制、语音对讲、智能分析等能力。 视频监控综合管理平台EasyCVR具备视频融合能力&#xff0c;平台基于云边端一体化架构&#xff0c;具有强大的…

JVM基础篇-方法区与运行时常量池

JVM基础篇-方法区与运行时常量池 方法区 Java 虚拟机有一个在所有 Java 虚拟机线程之间共享的方法区。方法区类似于传统语言的编译代码的存储区或者类似于操作系统进程中的“文本”段。它存储每个类的结构&#xff0c;例如运行时常量池、字段和方法数据&#xff0c;以及方法和…

图像处理库(Opencv, Matplotlib, PIL)以及三者之间的转换

文章目录 1. Opencv2. Matplotlib3. PIL4. 三者的区别和相互转换5. Torchvision 中的相关转换库5.1 ToPILImage([mode])5.2 ToTensor5.3 PILToTensor 1. Opencv opencv的基本图像类型可以和numpy数组相互转化&#xff0c;因此可以直接调用torch.from_numpy(img) 将图像转换成t…

Sql server 2005 卸载之后重新安装

Sql server 2005 卸载之后重新安装 Sql sercer 2005在重新安装之前先要进行卸载操作&#xff0c;由于Sql sercer 2005组件都是分散的&#xff0c;所以卸载时要找到对应的位置一个一个卸载&#xff0c;不卸载干净的情况下再次安装时会出现很多问题&#xff0c;导致安装失败。这…

KubeSphere部署芋道源码ruoyi-vue-pro

KubeSphere环境准备 新建企业空间 新建项目 创建harbor镜像服务信息 新建DevOps 项目 创建git,harbor,kubeconfig凭证 中间件部署 MySQL8部署redis6部署 后端部署 修改pom.xml <!-- pom.xml添加内容&#xff1a;--> <profiles><!-- 本地环境 --><pro…