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

Java设计模式 —— Java七大设计原则详解

文章目录

  • 前言
  • 一、单一职责原则
      • 1、概述
      • 2、案例演示
  • 二、接口隔离原则
      • 1、概述
      • 2、案例演示
  • 三、依赖倒转原则
      • 1、概述
      • 2、案例演示
  • 四、里氏替换原则
      • 1、概述
      • 2、案例演示
  • 五、开闭原则
      • 1、概述
      • 2、案例演示
  • 六、迪米特法则
      • 1、概述
      • 2、案例演示
  • 七、合成/聚合复用原则
      • 1、概述
      • 2、组合
      • 3、聚合
  • 总结


前言

编写软件过程中,程序员面临着来自耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性等多方面的挑战,设计模式是为了让程序(软件),具有更好的

  1. 代码重用性 (即:相同功能的代码,不用多次编写)
  2. 可读性 (即:编程规范性,便于其他程序员的阅读和理解)
  3. 可扩展性 (即:当需要增加新的功能时,非常的方便,称为可维护)
  4. 可靠性 (即:当我们增加新的功能后,对原来的功能没有影响)
  5. 使程序呈现高内聚低耦合的特性

由此才一步步发展出了设计模式,而设计模式又遵循着以下七大原则:

缩写名称定义
SRP单一职责原则一个类只负责一个功能领域中的相应职责
ISP接口隔离原则类之间的依赖关系应该建立在最小接口上
DIP依赖倒转(倒置)原则依赖于抽象,不能依赖于具体实现
LSP里氏替换原则所有引用基类的地方必须能透明地使用其子类对象
OCP开闭原则对扩展开放,对修改关闭
LOD迪米特法则一个软件实体应当尽可能少的与其他实体发生相互作用
CARP合成/聚合复用原则尽量使用合成/聚合,而不是通过继承达到复用的目的

一、单一职责原则

1、概述

单一职责原则:

对类来说的,即一个类应该只负责一项职责。如类A负责两个不同职责:职责1,职责2。当职责1需求变更而改变A时,可能造成职责2执行错误,所以需要将类A的粒度分解为A1,A2。

注意事项和细节:

  1. 降低类的复杂度,一个类只负责一项职责。
  2. 提高类的可读性,可维护性
  3. 降低变更引起的风险
  4. 通常情况下,我们应当遵守类的单一职责原则,只有逻辑足够简单,才可以在代码级违反单一职责原则;(只有类中方法数量足够少,可以在方法级别保持单一职责原则)

2、案例演示

错误演示:

//交通工具类
public class Vehicle{public void run(String vehicle){System.out.println(vehicle + " 在公路上运行");}
}

在上述代码中,不同类型的交通工具(海陆空),是现在同一个run方法中,这就违反了单一职责原则,如果其中某一类型交通工具的交通方式发生变更,其他的交通工具也会相应受到影响。

优化:

//陆地交通工具
public class RoadVehicle{public void run(String vehicle){System.out.println(vehicle + " 在公路上运行");}
}
//空中交通工具
public class AirVehicle{public void run(String vehicle){System.out.println(vehicle + " 在天空上运行");}
}
//水中交通工具
public class WaterVehicle{public void run(String vehicle){System.out.println(vehicle + " 在水中运行");}
}

在上述代码中,将类分解,在不同的类中实现不同的功能,这样即使其中一种发生变更,也不会影响到其他类的运行。


二、接口隔离原则

1、概述

接口隔离原则:

客户端不应该被迫依赖于它不使用的方法,即一个类对另一个类的依赖应该建立在最小的接口上。

2、案例演示

错误演示:

抽象接口:

public interface Interface1 {void operation1();void operation2();void operation3();void operation4();void operation5();
}

接口实现类B,D:

//B 实现接口1 并重写所有方法
public class B implements Interface1 {@Overridepublic void operation1() {System.out.println("B 实现了 operation1");}@Overridepublic void operation2() {System.out.println("B 实现了 operation2");}@Overridepublic void operation3() {System.out.println("B 实现了 operation3");}@Overridepublic void operation4() {System.out.println("B 实现了 operation4");}@Overridepublic void operation5() {System.out.println("B 实现了 operation5");}
}
//D 实现接口1 并重写所有方法
public class D implements Interface1 {@Overridepublic void operation1() {System.out.println("D 实现了 operation1");}@Overridepublic void operation2() {System.out.println("D 实现了 operation2");}@Overridepublic void operation3() {System.out.println("D 实现了 operation3");}@Overridepublic void operation4() {System.out.println("D 实现了 operation4");}@Overridepublic void operation5() {System.out.println("D 实现了 operation5");}
}

使用类:

//A 类通过接口 Interface1 依赖(使用)B类, 但是只会用到 1, 2, 3 方法
public class A {public void depend1(Interface1 myInterface){myInterface.operation1();}public void depend2(Interface1 myInterface){myInterface.operation2();}public void depend3(Interface1 myInterface){myInterface.operation3();}
}
//C 类通过接口 Interface1 依赖(使用)D类, 但是只会用到 1, 4, 5 方法
public class C {public void depend1(Interface1 myInterface){myInterface.operation1();}public void depend4(Interface1 myInterface){myInterface.operation4();}public void depend5(Interface1 myInterface){myInterface.operation5();}
}

上述代码的UML图为:

在这里插入图片描述
类A通过接口Interface1依赖类B,类C通过接口Interface1依赖类D,如果接口Interface1对于类A和类C来说不是最小接口,那么类B和类D必须去实现他们不需要的方法。

按隔离原则应当这样处理:将接口Interface1拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。案例如下:

优化:

抽象接口:

//接口1
public interface Interface1 {void operation1();
}
//接口2
public interface Interface2 {void operation2();void operation3();
}
//接口3
public interface Interface3 {void operation4();void operation5();
}

接口实现类B,D:

//B 实现接口1,2 并重写方法1,2,3
public class B implements Interface1, Interface2 {@Overridepublic void operation1() {System.out.println("B 实现了 operation1");}@Overridepublic void operation2() {System.out.println("B 实现了 operation2");}@Overridepublic void operation3() {System.out.println("B 实现了 operation3");}
}
//D 实现接口1,3 并重写方法1,4,5
public class D implements Interface1, Interface3 {@Overridepublic void operation1() {System.out.println("D 实现了 operation1");}@Overridepublic void operation4() {System.out.println("D 实现了 operation4");}@Overridepublic void operation5() {System.out.println("D 实现了 operation5");}
}

UML图如下:
在这里插入图片描述


三、依赖倒转原则

1、概述

依赖倒转原则:

  1. 高层模块不应该依赖低层模块,二者都应该依赖其抽象
  2. 抽象不应该依赖细节,细节应该依赖抽象
  3. 依赖倒转(倒置)的中心思想是面向接口编程
  4. 依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。
  5. 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成

2、案例演示

错误演示:

发信息者:

//发信息者
public class Person {//接收电子邮件public void receive(Email email){System.out.println(email.getInfo());}
}

电子邮件:

//电子邮件
public class Email {public String getInfo(){return "电子邮件信息: Hello World";}
}

上述代码指定了只能发送Email信息,如果我们获取的对象是微信,短信等等,则新增实现类,同时 Perons 也要增加相应的接收方法,

解决思路:引入一个抽象的接口 IReceiver, 表示接收者,这样 Person 类与接口 IReceiver 发生依赖

优化:

信息接口:

//信息接口
public interface IReceiver {String getInfo();
}

发信息者:

//发信息者
public class Person {//依赖抽象化,传入对象是IReceiver实现即可public void receive(IReceiver receiver){System.out.println(receiver.getInfo());}
}

信息类:

//Email信息
public class Email implements IReceiver{public String getInfo(){return "电子邮件信息: Hello World";}
}
//WeiXin信息
public class WeiXin implements IReceiver{public String getInfo(){return "微信信息: Hello World";}
}

在上述代码中,要想接收别的信息,只需增加具体实现类即可,一般情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序与实现细节的耦合度。


四、里氏替换原则

1、概述

里氏替换原则:

  1. 继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏。
  2. 继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障。
  3. 继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合、组合、依赖来解决问题。

2、案例演示

错误演示:

父类A:

public class A {//返回两个数的差public int func1(int a, int b){return a - b;}
}

子类B:

//增加了一个新功能:完成两个数相加,然后和9求和
public class B extends A {//修改父类方法@Overridepublic int func1(int a, int b) {return a + b;}public int func2(int a, int b){return func1(a, b) + 9;}
}

客户端:

public class Demo4_1 {public static void main(String[] args) {A a = new A();System.out.println("11-3=" + a.func1(11, 3));//11-3=8System.out.println("1-8=" + a.func1(1, 8));//1-8=-7A b = new B();System.out.println("1-8=" + b.func1(1, 8));//1-8=9 因子类重写父类方法导致错误}
}

(1)我们发现原来运行正常的相减功能发生了错误。原因就是类B无意中重写了父类的方法,造成原有功能出现错误,在实际编程中,我们常常会通过重写父类的方法完成新的功能,这样写起来虽然简单,但整个继承体系的复用性会比较差。特别是运行多态比较频繁的时候。

(2)通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖,聚合,组合等关系代替。

优化:

基类(公共抽象类):

public class Base {//把更加基础的方法和成员写到 Base类
}

类A:

public class A extends Base{public int func1(int a, int b){return a - b;}
}

类B:

public class B extends Base {//如果 B 需要使用 A 类的方法,使用组合关系private A a = new A();public int func1(int a, int b) {return a + b;}public int func2(int a, int b){return func1(a, b) + 9;}//仍想继续使用A的方法public int func3(int a, int b){return this.a.func1(a, b);}
}

客户端:

public class Demo4_2 {public static void main(String[] args) {A a = new A();System.out.println("11-3=" + a.func1(11, 3));//11-3=8System.out.println("1-8=" + a.func1(1, 8));//1-8=-7B b = new B();System.out.println("1+8=" + b.func1(1, 8));//1+8=9System.out.println("1+8+9=" + b.func2(1, 8));//1+8+9=18System.out.println("1-8=" + b.func3(1, 8));//1-8=-7}
}

五、开闭原则

1、概述

开闭原则:

  1. 开闭原则(Open Closed Principle)是编程中最基础、最重要的设计原则;
  2. 一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节;
  3. 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化;
  4. 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则

因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节可以从抽象派生来的实现类来进行扩展,当软件需要发生变化时,只需要根据需求重新派生一个实现类来扩展就可以了。

2、案例演示

错误演示:

图形基类:

public class Shape {int type;
}

图形类:

public class Rectangle extends Shape {Rectangle() {type = 1;}
}
public class Circle extends Shape {Circle() {type = 2;}
}
public class Triangle extends Shape {Triangle() {type = 3;}
}

画图工具:

//画图工具
public class GraphicEditor {public void drawShape(Shape shape){if (shape.type == 1){drawRectangle();}else if (shape.type == 2){drawCircle();}else if (shape.type == 3){drawTriangle();}}private void drawRectangle(){System.out.println("绘制矩形");}private void drawCircle(){System.out.println("绘制圆形");}private void drawTriangle(){System.out.println("绘制三角形");}
}
  1. 优点是比较好理解,简单易操作;
  2. 缺点是违反了设计模式的ocp原则,即对扩展开放(提供方),对修改关闭(使用方)
  3. 比如我们这时要新增加一个图形种类六变形,不仅需要新建图形类,还的修改GraphicEditor使用方代码使其能够使用六边形;
  4. 改进的思路:把创建Shape类做成抽象类,并提供一个抽象的draw方法,让子类去实现即可,这样我们有新的图形种类时,只需要让新的图形类继承Shape,并实现draw方法即可,使用方的代码就不需要修 -> 满足了开闭原则。

优化:

图形抽象父类:

public abstract class Shape {public abstract void draw();
}

图形类:

public class Rectangle extends Shape {@Overridepublic void draw() {System.out.println("绘制矩形");}
}
public class Circle extends Shape {@Overridepublic void draw() {System.out.println("绘制圆形");}
}
public class Triangle extends Shape {@Overridepublic void draw() {System.out.println("绘制三角形");}
}

画图工具:

public class GraphicEditor {public void drawShape(Shape shape){shape.draw();}
}

六、迪米特法则

1、概述

  1. 迪米特法则有个更简单的定义:只与直接的朋友通信,即一个对象应该对其他对象保持最少的了解,也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的public 方法,不对外泄露任何信息
  2. 类与类关系越密切,耦合度越大
  3. 每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。

2、案例演示

【例】明星与经纪人的关系实例

明星由于全身心投入艺术,所以许多日常事务由经纪人负责处理,如和粉丝的见面会,和媒体公司的业务洽淡等。这里的经纪人是明星的朋友,而粉丝和媒体公司是陌生人,所以适合使用迪米特法则。

明星类:

//明星类
public class Star {private String name;public Star(String name) {this.name=name;}public String getName() {return name;}
}

粉丝类:

//粉丝类
public class Fans {private String name;public Fans(String name) {this.name=name;}public String getName() {return name;}
}

媒体公司类:

//媒体公司类
public class Company {private String name;public Company(String name) {this.name=name;}public String getName() {return name;}
}

经纪人类:

//经纪人类
public class Agent {private Star star;private Fans fans;private Company company;public void setStar(Star star) {this.star = star;}public void setFans(Fans fans) {this.fans = fans;}public void setCompany(Company company) {this.company = company;}public void meeting() {System.out.println(fans.getName() + "与明星" + star.getName() + "见面了。");}public void business() {System.out.println(company.getName() + "与明星" + star.getName() + "洽淡业务。");}
}

客户端:

public class Demo6_1 {public static void main(String[] args) {Agent agent = new Agent();agent.setStar(new Star("鸡哥"));agent.setFans(new Fans("小黑子"));agent.setCompany(new Company("黑子公司"));agent.business();agent.meeting();}
}

七、合成/聚合复用原则

1、概述

合成复用原则是指:尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

通常类的复用分为继承复用和合成复用两种。

继承复用虽然有简单和易实现的优点,但它也存在以下缺点:

  1. 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。
  2. 子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。
  3. 它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化。

采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:

  1. 它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。
  2. 对象间的耦合度低。可以在类的成员位置声明抽象。
  3. 复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。

2、组合

组合(Composition) 表示的是’Part-od’的关系 : 父类拥有子类,子类不能独立于父类存在(声明在内部)

//明星类
public class Star {private String name;
}
//经纪人类
public class Agent {//明星类的生命周期与经纪人类一致private Star star;public Agent(){this.star = new Star();}
}

3、聚合

聚合(Aggregation)表示的是’Has-a’的关系 : 父类包含子类,子类可以独立于父类存在(外部传入)

//明星类
public class Star {private String name;
}
//经纪人类
public class Agent {//明星类是从外部传入与经纪人类的生命周期不一致private Star star;public void setStar(Star star) {this.star = star;}
}

总结

这7种设计原则是软件设计模式必须尽量遵循的原则,各种原则要求的侧重点不同:

  • 开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭。
  • 依赖倒置原则告诉我们要面向接口编程。
  • 单一职责原则告诉我们实现类要职责单一。
  • 接口隔离原则告诉我们在设计接口的时候要精简单一。
  • 迪米特法则告诉我们要降低耦合度。
  • 里氏替换原则告诉我们不要破坏继承体系。
  • 合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。
  • 参数类型,引用对象尽量使用接口或抽象类,而不是实现类,这主要是实现里氏替换原则的一个要求。

相关文章:

Java设计模式 —— Java七大设计原则详解

文章目录 前言一、单一职责原则1、概述2、案例演示 二、接口隔离原则1、概述2、案例演示 三、依赖倒转原则1、概述2、案例演示 四、里氏替换原则1、概述2、案例演示 五、开闭原则1、概述2、案例演示 六、迪米特法则1、概述2、案例演示 七、合成/聚合复用原则1、概述2、组合3、聚…...

SpringBoot学习记录(六)配置文件参数化

SpringBoot学习记录(六)配置文件参数化 一、参数提取到配置文件中二、yml配置文件三、ConfigurationProperties注解实现批量属性注入 一、参数提取到配置文件中 定义在代码中的参数的值分散在各个不同的文件中,不便于后期维护管理&#xff0…...

android 使用MediaPlayer实现音乐播放--获取音乐数据

前面已经添加了权限&#xff0c;有权限后可以去数据库读取音乐文件&#xff0c;一般可以获取全部音乐、专辑、歌手、流派等。 1. 获取全部音乐数据 class MusicHelper {companion object {SuppressLint("Range")fun getMusic(context: Context): MutableList<Mu…...

.net 8使用hangfire实现库存同步任务

C# 使用HangFire 第一章:.net Framework 4.6 WebAPI 使用Hangfire 第二章:net 8使用hangfire实现库存同步任务 文章目录 C# 使用HangFire前言项目源码一、项目架构二、项目服务介绍HangFire服务结构解析HangfireCollectionExtensions 类ModelHangfireSettingsHttpAuthInfoUs…...

第 22 章 - Go语言 测试与基准测试

在Go语言中&#xff0c;测试是一个非常重要的部分&#xff0c;它帮助开发者确保代码的正确性、性能以及可维护性。Go语言提供了一套标准的测试工具&#xff0c;这些工具可以帮助开发者编写单元测试、表达式测试&#xff08;通常也是指单元测试中的断言&#xff09;、基准测试等…...

VB.Net笔记-更新ing

目录 1.1 设置默认VS的开发环境为VB.NET&#xff08;2024/11/18&#xff09; 1.2 新建一个“Hello&#xff0c;world”的窗体&#xff08;2024/11/18&#xff09; 1.3 计算圆面积的小程序&#xff08;2024/11/18&#xff09; 显示/隐式 声明 &#xff08;2024/11/18&…...

centos 服务器 docker 使用代理

宿主机使用代理 在宿主机的全局配置文件中添加代理信息 vim /etc/profile export http_proxyhttp://127.0.0.1:7897 export https_proxyhttp://127.0.0.1:7897 export no_proxy"localhost,127.0.0.1,::1,172.171.0.0" docker 命令使用代理 例如我想在使用使用 do…...

python语言基础

1. 基础语法 Q: Python 中的变量与数据类型有哪些&#xff1f; A: Python 支持多种数据类型&#xff0c;包括数字&#xff08;整数 int、浮点数 float、复数 complex&#xff09;、字符串 str、列表 list、元组 tuple、字典 dict 和集合 set。每种数据类型都有其特定的用途和…...

Python中的Apriori库详解

文章目录 Python中的Apriori库详解一、引言二、Apriori算法原理与Python实现1、Apriori算法原理2、Python实现1.1、数据准备1.2、转换数据1.3、计算频繁项集1.4、提取关联规则 三、案例分析1、导入必要的库2、准备数据集3、数据预处理4、应用Apriori算法5、生成关联规则6、打印…...

MongoDB比较查询操作符中英对照表及实例详解

mongodb比较查询操作符中英表格一览表 NameDescription功能$eqMatches values that are equal to a specified value.匹配值等于指定值。$gtMatches values that are greater than a specified value.匹配值大于指定值。$gteMatches values that are greater than or equal to…...

掌上单片机实验室 – RT-Thread + ROS2 初探(25)

在初步尝试RT-Thread之后&#xff0c;一直在琢磨如何进一步感受它的优点&#xff0c;因为前面只是用了它的内核&#xff0c;感觉和FreeRTOS、uCOS等RTOS差别不大&#xff0c;至于它们性能、可靠性上的差异&#xff0c;在这种学习性的程序中&#xff0c;很难有所察觉。 RT-Threa…...

‌Kotlin中的?.和!!主要区别

目录 1、?.和!!介绍 2、使用场景和最佳实践 3、代码示例和解释 1、?.和!!介绍 ‌Kotlin中的?.和!!主要区别在于它们对空指针的处理方式。‌ ‌?.&#xff08;安全调用操作符&#xff09;‌&#xff1a;当变量可能为null时&#xff0c;使用?.可以安全地调用其方法或属性…...

iframe嵌入踩坑记录

iframe嵌入父子页面token问题 背景介绍 最近在做在平台A中嵌入平台B某个页面的需求&#xff0c;我负责的是平台B这边&#xff0c;使这个页面被嵌入后能正常使用。两个平台都实现了单点登录。 其实这是第二次做这个功能了&#xff0c;原本以为会很顺利&#xff0c;但没想到折腾…...

面试小札:Java的类加载过程和类加载机制。

Java类加载过程 加载&#xff08;Loading&#xff09; 这是类加载过程的第一个阶段。在这个阶段&#xff0c;Java虚拟机&#xff08;JVM&#xff09;主要完成三件事&#xff1a; 通过类的全限定名来获取定义此类的二进制字节流。这可以从多种来源获取&#xff0c;如本地文件系…...

Spring 上下文对象

1. Spring 上下文对象概述 Spring 上下文对象&#xff08;ApplicationContext&#xff09;是 Spring 框架的核心接口之一&#xff0c;它扩展了 BeanFactory 接口&#xff0c;提供了更多企业级应用所需的功能。ApplicationContext 不仅可以管理 Bean 的生命周期和配置&#xff0…...

Wireshark抓取HTTPS流量技巧

一、工具准备 首先安装wireshark工具&#xff0c;官方链接&#xff1a;Wireshark Go Deep 二、环境变量配置 TLS 加密的核心是会话密钥。这些密钥由客户端和服务器协商生成&#xff0c;用于对通信流量进行对称加密。如果能通过 SSL/TLS 日志文件&#xff08;例如包含密钥的…...

测试人员--如何区分前端BUG和后端BUG

在软件测试中&#xff0c;发现一个BUG并不算难&#xff0c;但准确定位它的来源却常常让测试人员头疼。是前端页面的问题&#xff1f;还是后台服务的异常&#xff1f;如果搞错了方向&#xff0c;开发人员之间的沟通效率会大大降低&#xff0c;甚至导致问题久拖不决。 那么&#…...

【Vue】指令扩充(指令修饰符、样式绑定)

目录 指令修饰符 按键修饰符 事件修饰符 双向绑定指令修饰符 输入框 表单域 下拉框 单选按钮 复选框 样式绑定 分类 绑定class 绑定style tab页切换示例 指令修饰符 作用 借助指令修饰符&#xff0c;可以让指令的功能更强大 分类 按键修饰符&#xff1a;用来…...

Ubuntu20.04 Rk3588 交叉编译ffmpeg7.0

firefly 公司出的rk3588的设备&#xff0c;其中已经安装了gcc 交叉编译工具&#xff0c;系统版本是Ubuntu20.04。 使用Ubuntu20.04 交叉编译ffmpeg_ubuntu下配置ffmpeg交叉编译器为arm-linux-gnueabihf-gcc-CSDN博客文章浏览阅读541次。ubuntu20.04 交叉编译ffmpeg_ubuntu下配…...

HTML常用表格与标签

一、table表格标签&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <!--有大小为1的边框--> <table border"1">…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

地震勘探——干扰波识别、井中地震时距曲线特点

目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波&#xff1a;可以用来解决所提出的地质任务的波&#xff1b;干扰波&#xff1a;所有妨碍辨认、追踪有效波的其他波。 地震勘探中&#xff0c;有效波和干扰波是相对的。例如&#xff0c;在反射波…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...