瑞_23种设计模式_访问者模式

文章目录

    • 1 访问者模式(Visitor Pattern)
      • 1.1 介绍
      • 1.2 概述
      • 1.3 访问者模式的结构
      • 1.4 访问者模式的优缺点
      • 1.5 访问者模式的使用场景
    • 2 案例一
      • 2.1 需求
      • 2.2 代码实现
    • 3 案例二
      • 3.1 需求
      • 3.2 代码实现
    • 4 拓展——双分派
      • 4.1 分派
      • 4.2 动态分派(多态)
      • 4.3 静态分派(重载)
      • 4.4 双分派

🙊 前言:本文章为瑞_系列专栏之《23种设计模式》的访问者模式篇。本文中的部分图和概念等资料,来源于博主学习设计模式的相关网站《菜鸟教程 | 设计模式》和《黑马程序员Java设计模式详解》,特此注明。本文中涉及到的软件设计模式的概念、背景、优点、分类、以及UML图的基本知识和设计模式的6大法则等知识,建议阅读 《瑞_23种设计模式_概述》

本系列 - 设计模式 - 链接:《瑞_23种设计模式_概述》

⬇️本系列 - 创建型模式 - 链接🔗

  单例模式:《瑞_23种设计模式_单例模式》
  工厂模式:《瑞_23种设计模式_工厂模式》
  原型模式:《瑞_23种设计模式_原型模式》
抽象工厂模式:《瑞_23种设计模式_抽象工厂模式》
 建造者模式:《瑞_23种设计模式_建造者模式》

⬇️本系列 - 结构型模式 - 链接🔗

  代理模式:《瑞_23种设计模式_代理模式》
 适配器模式:《瑞_23种设计模式_适配器模式》
 装饰者模式:《瑞_23种设计模式_装饰者模式》
  桥接模式:《瑞_23种设计模式_桥接模式》
  外观模式:《瑞_23种设计模式_外观模式》
  组合模式:《瑞_23种设计模式_组合模式》
  享元模式:《瑞_23种设计模式_享元模式》

⬇️本系列 - 行为型模式 - 链接🔗

模板方法模式:《瑞_23种设计模式_模板方法模式》
  策略模式:《瑞_23种设计模式_策略模式》
  命令模式:《瑞_23种设计模式_命令模式》
 职责链模式:《瑞_23种设计模式_职责链模式》
  状态模式:《瑞_23种设计模式_状态模式》
 观察者模式:《瑞_23种设计模式_观察者模式》
 中介者模式:《瑞_23种设计模式_中介者模式》
 迭代器模式:《瑞_23种设计模式_迭代器模式》
 访问者模式:《后续更新》
 备忘录模式:《后续更新》
 解释器模式:《后续更新》

在这里插入图片描述

1 访问者模式(Visitor Pattern)

  在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。

  瑞:行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。
  瑞:行为型模式分为类行为模式对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性

访问者模式属于:对象行为模式

1.1 介绍

  • 意图:主要将数据结构与数据操作分离。

  • 主要解决:稳定的数据结构和易变的操作耦合问题。

  • 何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。

  • 如何解决:在被访问的类里面加一个对外提供接待访问者的接口。

  • 关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。

  • 应用实例
      您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。

  • 优点
      1️⃣ 符合单一职责原则。
      2️⃣ 优秀的扩展性。
      3️⃣ 灵活性。

  • 缺点
      1️⃣ 具体元素对访问者公布细节,违反了迪米特原则。
      2️⃣ 具体元素变更比较困难。
      3️⃣ 违反了依赖倒置原则,依赖了具体类,没有依赖抽象。

  • 使用场景
      1️⃣ 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。
      2️⃣ 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,也不希望在增加新操作时修改这些类。

  • 注意事项
      1️⃣ 访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。

1.2 概述

定义:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。

  访问者模式的主要思想是将一些作用于某种数据结构中的各元素的操作封装起来,使得可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

  在访问者模式中,针对系统中拥有固定类型数的对象结构(元素),在其内提供一个accept()方法来接受访问者对象的访问。不同的访问者对同一个元素的访问内容是不同的,这使得相同的元素集合可以产生不同的数据结果。

1.3 访问者模式的结构

  • 访问者模式主要包含以下角色:
      1️⃣ 抽象访问者(Visitor)角色:定义了对每一个元素(Element)访问的行为,它的参数就是可以访问的元素,它的方法个数理论上来讲与元素类个数(Element的实现类个数)是一样的,从这点不难看出,访问者模式要求元素类的个数不能改变。
      2️⃣ 具体访问者(ConcreteVisitor)角色:给出对每一个元素类访问时所产生的具体行为。
      3️⃣ 抽象元素(Element)角色:定义了一个接受访问者的方法(accept),其意义是指,每一个元素都要可以被访问者访问。
      4️⃣ 具体元素(ConcreteElement)角色: 提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。
      5️⃣ 对象结构(Object Structure)角色:定义当中所提到的对象结构,对象结构是一个抽象表述,具体点可以理解为一个具有容器性质或者复合对象特性的类,它会含有一组元素(Element),并且可以迭代这些元素,供访问者访问。

1.4 访问者模式的优缺点

优点

  • 扩展性好
    在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。

  • 复用性好
    通过访问者来定义整个对象结构通用的功能,从而提高复用程度。

  • 分离无关行为
    通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。

缺点

  • 对象结构变化很困难
    在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。

  • 违反了依赖倒置原则
    访问者模式依赖了具体类,而没有依赖抽象类。

1.5 访问者模式的使用场景

  • 对象结构相对稳定,但其操作算法经常变化的程序。
  • 对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构。



2 案例一

【案例】给宠物喂食

2.1 需求

  现在养宠物的人特别多,我们就以这个为例,当然宠物还分为狗,猫等,要给宠物喂食的话,主人可以喂,其他人也可以喂食。

  • 访问者角色:给宠物喂食的人
  • 具体访问者角色:主人、其他人
  • 抽象元素角色:动物抽象类
  • 具体元素角色:宠物狗、宠物猫
  • 结构对象角色:主人家

  类图如下:

在这里插入图片描述

2.2 代码实现

  创建抽象访问者接口

抽象访问者角色类(接口)
/*** 抽象访问者角色类** @author LiaoYuXing-Ray**/
public interface Person {// 喂食宠物狗void feed(Cat cat);// 喂食宠物猫void feed(Dog dog);
}

  创建不同的具体访问者角色(主人和其他人),都需要实现 Person接口

具体访问者角色类(自己)(类)
/*** 具体访问者角色类(自己)** @author LiaoYuXing-Ray**/
public class Owner implements Person {public void feed(Cat cat) {System.out.println("主人喂食猫");}public void feed(Dog dog) {System.out.println("主人喂食狗");}
}
具体访问者角色类(其他人)(类)
/*** 具体访问者角色类(其他人)** @author LiaoYuXing-Ray**/
public class Someone implements Person {public void feed(Cat cat) {System.out.println("其他人喂食猫");}public void feed(Dog dog) {System.out.println("其他人喂食狗");}
}

  定义抽象节点 – 宠物

抽象元素角色类(接口)
/*** 抽象元素角色类** @author LiaoYuXing-Ray**/
public interface Animal {// 接受访问者访问的功能void accept(Person person);
}

  定义实现Animal接口的 具体节点(元素)

具体元素角色类(宠物猫)(类)
/*** 具体元素角色类(宠物猫)** @author LiaoYuXing-Ray**/
public class Cat implements Animal {public void accept(Person person) {person.feed(this);// 访问者给宠物猫喂食System.out.println("好好吃,喵喵喵。。。");}
}
具体元素角色类(宠物狗)(类)
/*** 具体元素角色类(宠物狗)** @author LiaoYuXing-Ray**/
public class Dog implements Animal {public void accept(Person person) {person.feed(this);// 访问者给宠物猫喂食System.out.println("好好吃,汪汪汪。。。");}
}

  定义对象结构,此案例中就是主人的家

对象结构类(类)
import java.util.ArrayList;
import java.util.List;/*** 对象结构类** @author LiaoYuXing-Ray**/
public class Home {// 声明一个集合对象,用来存储元素对象private final List<Animal> nodeList = new ArrayList<Animal>();// 添加元素功能public void add(Animal animal) {nodeList.add(animal);}public void action(Person person) {// 遍历集合,获取每一个元素,让访问者访问每一个元素for (Animal animal : nodeList) {animal.accept(person);}}
}
测试类
/*** 测试类** @author LiaoYuXing-Ray**/
public class Client {public static void main(String[] args) {// 创建Home对象Home home = new Home();//添加元素到Home对象中home.add(new Dog());home.add(new Cat());// 创建主人对象Owner owner = new Owner();Someone someone = new Someone();// 让主人喂食所有的宠物home.action(owner);home.action(someone);}
}

  代码运行结果如下:

	主人喂食狗好好吃,汪汪汪。。。主人喂食猫好好吃,喵喵喵。。。其他人喂食狗好好吃,汪汪汪。。。其他人喂食猫好好吃,喵喵喵。。。

3 案例二

本案例为菜鸟教程中的案例

3.1 需求

  我们将创建一个定义接受操作的 ComputerPart 接口。Keyboard、Mouse、Monitor 和 Computer 是实现了 ComputerPart 接口的实体类。我们将定义另一个接口 ComputerPartVisitor,它定义了访问者类的操作。Computer 使用实体访问者来执行相应的动作。

  VisitorPatternDemo,我们的演示类使用 Computer、ComputerPartVisitor 类来演示访问者模式的用法。

在这里插入图片描述

3.2 代码实现

步骤 1

  定义一个表示元素的接口。

ComputerPart.java
public interface ComputerPart {public void accept(ComputerPartVisitor computerPartVisitor);
}

步骤 2

  创建扩展了上述类的实体类。

Keyboard.java
public class Keyboard  implements ComputerPart {@Overridepublic void accept(ComputerPartVisitor computerPartVisitor) {computerPartVisitor.visit(this);}
}
Monitor.java
public class Monitor  implements ComputerPart {@Overridepublic void accept(ComputerPartVisitor computerPartVisitor) {computerPartVisitor.visit(this);}
}
Mouse.java
public class Mouse  implements ComputerPart {@Overridepublic void accept(ComputerPartVisitor computerPartVisitor) {computerPartVisitor.visit(this);}
}
Computer.java
public class Computer implements ComputerPart {ComputerPart[] parts;public Computer(){parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};      } @Overridepublic void accept(ComputerPartVisitor computerPartVisitor) {for (int i = 0; i < parts.length; i++) {parts[i].accept(computerPartVisitor);}computerPartVisitor.visit(this);}
}

步骤 3

  定义一个表示访问者的接口。

ComputerPartVisitor.java
public interface ComputerPartVisitor {public void visit(Computer computer);public void visit(Mouse mouse);public void visit(Keyboard keyboard);public void visit(Monitor monitor);
}

步骤 4

  创建实现了上述类的实体访问者。

ComputerPartDisplayVisitor.java
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {@Overridepublic void visit(Computer computer) {System.out.println("Displaying Computer.");}@Overridepublic void visit(Mouse mouse) {System.out.println("Displaying Mouse.");}@Overridepublic void visit(Keyboard keyboard) {System.out.println("Displaying Keyboard.");}@Overridepublic void visit(Monitor monitor) {System.out.println("Displaying Monitor.");}
}

步骤 5

  使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。

VisitorPatternDemo.java
public class VisitorPatternDemo {public static void main(String[] args) {ComputerPart computer = new Computer();computer.accept(new ComputerPartDisplayVisitor());}
}

步骤 6

  执行程序,输出结果:

	Displaying Mouse.Displaying Keyboard.Displaying Monitor.Displaying Computer.



4 拓展——双分派

访问者模式用到了一种双分派的技术。

4.1 分派

  变量被声明时的类型叫做变量的静态类型,有些人又把静态类型叫做明显类型;而变量所引用的对象的真实类型又叫做变量的实际类型。比如 Map map = new HashMap() ,map变量的静态类型是 Map ,实际类型是 HashMap 。根据对象的类型而对方法进行的选择,就是分派(Dispatch),分派(Dispatch)又分为两种,即静态分派和动态分派。

  • 静态分派(Static Dispatch) :发生在编译时期,分派根据静态类型信息发生。静态分派对于我们来说并不陌生,方法重载就是静态分派。

  • 动态分派(Dynamic Dispatch): 发生在运行时期,动态分派动态地置换掉某个方法。Java通过方法的重写(多态)支持动态分派。

4.2 动态分派(多态)

通过方法的重写(多态)支持动态分派。

public class Animal {public void execute() {System.out.println("Animal");}
}public class Dog extends Animal {@Overridepublic void execute() {System.out.println("dog");}
}public class Cat extends Animal {@Overridepublic void execute() {System.out.println("cat");}
}public class Client {public static void main(String[] args) {Animal a = new Dog();a.execute();Animal a1 = new Cat();a1.execute();}
}

  执行程序,输出结果:

	dogcat

  上面代码的结果大家应该直接可以说出来,这不就是多态吗!运行执行的是子类中的方法。

  Java编译器在编译时期并不总是知道哪些代码会被执行,因为编译器仅仅知道对象的静态类型,而不知道对象的真实类型;而方法的调用则是根据对象的真实类型,而不是静态类型。

4.3 静态分派(重载)

通过方法重载支持静态分派。

public class Animal {
}public class Dog extends Animal {
}public class Cat extends Animal {
}public class Execute {public void execute(Animal a) {System.out.println("Animal");}public void execute(Dog d) {System.out.println("dog");}public void execute(Cat c) {System.out.println("cat");}
}public class Client {public static void main(String[] args) {Animal a = new Animal();Animal a1 = new Dog();Animal a2 = new Cat();Execute exe = new Execute();exe.execute(a);exe.execute(a1);exe.execute(a2);}
}

  执行程序,输出结果:

	AnimalAnimalAnimal

  这个结果可能出乎一些你的意料了吧~

  因为重载方法的分派是根据静态类型进行的,这个分派过程在编译时期就完成了。

4.4 双分派

所谓双分派技术就是在选择一个方法的时候,不仅仅要根据消息接收者(receiver)的运行时区别,还要根据参数的运行时区别。

public class Animal {public void accept(Execute exe) {exe.execute(this);}
}public class Dog extends Animal {public void accept(Execute exe) {exe.execute(this);}
}public class Cat extends Animal {public void accept(Execute exe) {exe.execute(this);}
}public class Execute {public void execute(Animal a) {System.out.println("animal");}public void execute(Dog d) {System.out.println("dog");}public void execute(Cat c) {System.out.println("cat");}
}public class Client {public static void main(String[] args) {Animal a = new Animal();Animal d = new Dog();Animal c = new Cat();Execute exe = new Execute();a.accept(exe);d.accept(exe);c.accept(exe);}
}

  在上面代码中,客户端将 Execute 对象做为参数传递给 Animal 类型的变量调用的方法,这里完成第一次分派,这里是方法重写,所以是动态分派,也就是执行实际类型中的方法,同时也将自己this作为参数传递进去,这里就完成了第二次分派,这里的 Execute 类中有多个重载的方法,而传递进行的是this,就是具体的实际类型的对象。

  说到这里,我们已经明白双分派是怎么回事了,但是它有什么效果呢?就是可以实现方法的动态绑定,我们可以对上面的程序进行修改。运行结果如下:

  执行程序,输出结果:

	animaldogcat

双分派实现动态绑定的本质,就是在重载方法委派的前面加上了继承体系中覆盖的环节,由于覆盖是动态的,所以重载就是动态的了




本文是博主的粗浅理解,可能存在一些错误或不完善之处,如有遗漏或错误欢迎各位补充,谢谢

  如果觉得这篇文章对您有所帮助的话,请动动小手点波关注💗,你的点赞👍收藏⭐️转发🔗评论📝都是对博主最好的支持~


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

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

相关文章

4.网络编程-websocket(golang)

目录 什么是websocket golang中使用websocket Server端 Client端 什么是websocket WebSocket是一种在互联网上提供全双工通信的协议&#xff0c;即允许服务器和客户端之间进行双向实时通信的网络技术。它是作为HTML5的一部分标准化的&#xff0c;旨在解决传统HTTP协议在实…

工程中实践的微服务设计模式

大家好&#xff0c;我是 方圆。最近在读《微服务架构设计模式》&#xff0c;开始的时候我非常的好奇&#xff0c;因为在我印象中&#xff0c;设计模式是常说的那23种设计模式&#xff0c;而微服务的设计模式又是什么呢&#xff1f;这个问题也留给大家&#xff0c;在文末我会附上…

opencv图像处理技术(阈值处理与图像平滑)

进行图像处理时&#xff0c;常常需要对图像进行预处理以提取所需的信息或改善图像质量。阈值处理和图像平滑是两种常见的预处理技术。 阈值处理 阈值处理是一种图像分割技术&#xff0c;其基本思想是将图像中的像素值与一个或多个预先设定的阈值进行比较&#xff0c;根据比较…

【人工智能】猫狗识别

猫狗识别 实验背景 数据集介绍 我们使用CIFAR10数据集。CIFAR10数据集包含60,000张32x32的彩色图片&#xff0c;10个类别&#xff0c;每个类包含6,000张。其中50,000张图片作为训练集&#xff0c;10000张作为验证集。这次我们只对其中的猫和狗两类进行预测。 图 1 CIFAR10 数据…

Windows11配置VUE开发环境

目录 一、按照nodejs二、命令安装npm cache clean --forcenpm install -g vue/clinpm install npm -gnpm install webpacknpm install vue-cli -g与npm install -g vue/cli区别npm install -g cnpm --registryhttps://registry.npm.taobao.orgnpm i yarn -g --verbosenpm i -g …

网络与并发编程(一)

并发编程介绍_串行_并行_并发的区别 串行、并行与并发的区别 串行(serial)&#xff1a;一个CPU上&#xff0c;按顺序完成多个任务并行(parallelism)&#xff1a;指的是任务数小于等于cpu核数&#xff0c;即任务真的是一起执行的并发(concurrency)&#xff1a;一个CPU采用时间…

IDEA 导出jar无法执行 错误: 找不到或无法加载主类

1、首先配置正确Project Struct 保证需要引用的jar包库添加到Libraries里&#xff0c;尽管添加到Modules里依然可以测试运行或调试&#xff0c;但导出的jar包会遇到问题。 2、导出jar&#xff0c;方式选择如下 选择”From modules with dependencies" 然后去掉以上“Extr…

手机如何在线制作gif?轻松一键在线操作

现在大家都喜欢使用手机来拍摄记录有趣的事物&#xff0c;但是时间长了手机里的视频越来越多导致手机存储空间不够了&#xff0c;这些视频又不想删除时应该怎么办呢&#xff1f;这个很简单&#xff0c;下面就给大家分享一款不用下载手机就能操作的视频转gif网站-GIF中文网&…

【贪玩巴斯】Mac的M芯片(M1/2...)下载homebrew方法(24年最新且已验证可行)

1. 按照目前广为流传的方法&#xff08;M1会出现一些问题&#xff09;&#xff1a; 终端输入&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 使用国内镜像下载。 2. 输入后按照要求步骤执行即可&#xff…

k8s单节点部署,容器运行时使用containerd

环境 系统 &#xff1a; entOS Linux release 7.9.2009 (CoreIP&#xff1a;192.168.44.177 硬件要求&#xff1a;控制平面最少需要 2c2g 安装前环境准备 如果是集群部署还需要配置时间同步 关闭防火墙 systemctl disable firewalld关闭selinux setenforce 0sed -i s/SELI…

Vue - 你知道Vue组件中的data为什么是一个函数吗

难度级别:中高级及以上 提问概率:80% 在Vue项目中,App.vue下的每个子组件都会生成一个单独的Vue实例对象,但这些子对象都是通过通过vue.extend方法创建而来的,也就是说我们平时在项目中所定义的Vue组件,都有一个相同的父类对象。这样也就…

JS-PC/MOBILE技巧--PC

一、PC 端网页特效 1、元素偏移量 offset 系列 offset 概述 offset 就是偏移量&#xff0c;使用 offset 系列相关属性可以动态的得到该元素的位置&#xff08;偏移&#xff09;、大小等。 获取元素距离带有定位父元素的位置获取元素自身的大小&#xff08;宽度高度&#xff0…

前端入门(认识HTML,CSS,JavaScript三件套)

目录 前言 HTML&#xff08;构建&#xff09; CSS&#xff08;设计&#xff09; JavaScript&#xff08;互动&#xff09; 总结 相关书籍推荐 前言 前端&#xff08;Frontend&#xff09;指的是与用户直接交互的部分&#xff0c;也称为客户端。在网站或者应用程序中&…

特别详细的Spring Cloud 系列教程1:服务注册中心Eureka的启动

Eureka已经被Spring Cloud继承在其子项目spring-cloud-netflix中&#xff0c;搭建Eureka Server的方式还是非常简单的。只需要通过一个独立的maven工程即可搭建Eureka Server。 我们引入spring cloud的依赖和eureka的依赖。 <dependencyManagement><!-- spring clo…

如何成为一名优秀的工程师下

身为工程师&#xff0c;理所当然要重视实践&#xff0c;自然科学不管发展到何时都离不开实验。 电子学本身就是 为了指导工程实践。所以不要谈空洞的理论。现在很多毕业生都面临这样的问题&#xff0c;总是谈一些空洞的理论&#xff0c;甚至错误的但还不以为然的理论。实践可以…

uniapp 密码框的眼睛

效果展示&#xff1a; uniapp input 官网链接&#xff1a;链接 按照官方文档&#xff0c;uni-icon出不来。 通过自己的方法解决了&#xff0c;解决方案如下&#xff1a; 代码&#xff1a; <uni-forms-item name"password"><inputclass"uni-input&quo…

Spring AI 来了,打造Java生态大模型应用开发新框架!

Spring AI 来了&#xff0c;打造Java生态大模型应用开发新框架&#xff01; Spring AI 开发框架设计理念Spring AI 主要功能特性如下 Spring AI 应用开发案例案例一&#xff1a;基于大模型的对话应用开发案例二&#xff1a;RAG 检索增强应用开发案例三&#xff1a;Function Cal…

15-1-Flex布局

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 Flex布局1 Flex容器和Flex项目2 Flex 容器属性2.1 主轴的方向2.2 主轴对齐方式…

vscode-插件开发-hello world-创建初始模板

参考vscode官方示例&#xff1a;如何创建你的第一个插件开发项目模板的步骤进行了下文操作。 目录 前言1.环境配置全局安装 yo, generator-code 2. 新建一个插件项目模板问题1: F5 按键无法启动launch.json调试(解决)问题1 描述:问题1: 找错误问题1: 可行的解决方案 3. 开发插…

SpringBoot集成Redis快速入门Demo

目录 1. Redis概述 2.下载安装 3. Spring-data-redis概述 4. 快速入门 4.1 创建工程 4.2 导入依赖 4.3 添加配置文件 4.4 添加Redis配置 4.5 添加Redis工具类 4.6 添加测试类 5. Demo下载地址 1. Redis概述 Redis&#xff08;Remote Dictionary Server 远程…