设计模式の软件设计原则
文章目录
- 前言
- 一、聚合&组合&继承&依赖
- 1.1、继承
- 1.2、组合
- 1.3、聚合
- 1.4、依赖
- 二、单一职责原则
- 2.1、单一职责原则反面案例
- 2.2、单一职责原则反面案例的改进
- 三、接口隔离原则
- 3.1、接口隔离原则反面案例
- 3.2、接口隔离原则反面案例的改进
- 四、依赖倒转原则
- 4.1、依赖倒转原则反面案例
- 4.1、依赖倒转原则反面案例的改进
- 五、里氏替换原则
- 5.1、里氏替换原则反面案例
- 5.2、里氏替换原则反面案例的改进
- 六、开闭原则
- 6.1、开闭原则反面案例
- 6.2、开闭原则反面案例的改进
- 七、迪米特原则
- 7.1、迪米特原则反面案例
- 7.2、迪米特原则反面案例的改进
- 八、合成复用原则
- 8.1、合成复用原则反面案例
- 8.2、合成复用原则反面案例的改进
前言
本篇是设计模式专题笔记的前置理论篇,介绍软件设计的七大原则:单一职责原则、接口隔离原则、依赖倒转原则、里氏替换原则、开闭原则、迪米特法则、合成复用原则。上述七大原则,既是软件设计的原则,也是总结出23种设计模式的核心思想。不仅是学习设计模式的前置理论,更是对Java面向对象三大特征的延伸扩展。
一、聚合&组合&继承&依赖
在介绍七大原则之前,首先需要明白什么是聚合、组合、依赖、继承。
1.1、继承
继承是面向对象的三大特征之一。A类继承了B类,就拥有了B类的一切特征。如果A类重写了B类的某个方法,该方法在A中会以重写的生效。很多中间件、框架的自定义配置,即是用自定义类继承框架中原有的父类,重写其中的方法。
但是使用继承,很大程度上也会破坏七大原则,应该慎用继承。个人理解,何时使用继承,最简单的就是,学生类可以继承人类,猫不能继承人类。
即:没有共性的类之间,不要使用继承,如果两者之间只是代码相似,可以用组合代替继承。
1.2、组合
组合是一种强“拥有”关系,表示一个类完全负责
另一个类的生命周期,包含的对象依附于整体对象存在。这种关系通常用来描述“整体-部分”关系,且部分对象
不可分离。整体销毁时部分对象也随之销毁:(因为部分对象
是在整体对象
中创建的。)
class Engine {public void start() {System.out.println("Engine starts.");}
}class Car {private Engine engine;public Car() { // 组合关系,Car 自己创建 Enginethis.engine = new Engine();}public void start() {engine.start();System.out.println("Car starts.");}
}public class CompositionExample {public static void main(String[] args) {Car car = new Car(); // Car 创建并拥有 Enginecar.start();}
}
1.3、聚合
聚合是一种弱“拥有”关系,表示一个类包含另一个类的对象作为其属性,但被包含对象可以独立存在。整体并不控制部分的生命周期。
class Engine {public void start() {System.out.println("Engine starts.");}
}class Car {private Engine engine;public Car(Engine engine) { // 通过构造方法传递 Enginethis.engine = engine;}public void start() {engine.start();System.out.println("Car starts.");}
}public class AggregationExample {public static void main(String[] args) {Engine engine = new Engine(); // Engine 可以独立存在Car car = new Car(engine); // Car 聚合了 Enginecar.start();}
}
1.4、依赖
依赖是一种非常松散的关系,表示一个类使用另一个类的功能,但它们的生命周期彼此独立。
class Printer {public void printDocument(String document) {System.out.println("Printing: " + document);}
}class User {public void usePrinter(Printer printer, String document) {printer.printDocument(document);}
}public class DependencyExample {public static void main(String[] args) {Printer printer = new Printer(); // 创建 Printer 对象User user = new User(); // 创建 User 对象user.usePrinter(printer, "My Document"); // User 依赖于 Printer 的功能}
}
二、单一职责原则
单一职责原则
的核心思想在于,一个类,或下推到一个方法,只去做一件事,或者一类逻辑相同的事情。注意,此一件事,并不代表一个类中只能存在一个方法。例如我们有一个OrderService
,顾名思义,应该在该类中做和订单相关的操作,比如下单,修改订单状态,撤单等。而不是再混入一些用户相关操作。
2.1、单一职责原则反面案例
/*** 单一职责原则案例1*/
public class Demo1 {public static void main(String[] args) {Vehicle vehicle = new Vehicle();vehicle.run("汽车");vehicle.run("船");vehicle.run("飞机");}
}/*** 违反单一职责原则,不同类的交通工具都打出了在公路上行驶* 实际上各自的行驶方式是不一样的* 这种写法把所有的情况都笼统地放在了一个方法中*/
class Vehicle{public void run(String vehicle){System.out.println(vehicle + "在公路上行驶");}
}
2.2、单一职责原则反面案例的改进
/*** 单一职责原则案例2* 这种方式是在类的层面上进行了拆分* 将不同的交通工具的行驶方式,拆分到了不同的类中* 在结构简单,每个类中代码量少的时候,没必要*/
public class Demo2 {public static void main(String[] args) {RoadVehicle roadVehicle = new RoadVehicle();roadVehicle.run("汽车");AirVehicle airVehicle = new AirVehicle();airVehicle.run("飞机");WaterVehicle waterVehicle = new WaterVehicle();waterVehicle.run("船");}
}class RoadVehicle{public void run(String vehicle){System.out.println(vehicle + "在公路上行驶");}
}class AirVehicle{public void run(String vehicle){System.out.println(vehicle + "在天空中飞行");}
}class WaterVehicle{public void run(String vehicle){System.out.println(vehicle + "在水上航行");}
}
/*** 单一职责原则案例3**/
public class Demo3 {public static void main(String[] args) {Vehicle2 vehicle2 = new Vehicle2();vehicle2.airRun("飞机");vehicle2.roadRun("汽车");vehicle2.waterRun("船");}
}/*** 这种方式是在方法层面进行了拆分,每个方法只做一件事*/
class Vehicle2{public void roadRun(String vehicle){System.out.println(vehicle + "在公路上行驶");}public void airRun(String vehicle){System.out.println(vehicle + "在天空中飞行");}public void waterRun(String vehicle){System.out.println(vehicle + "在水上航行");}
}
三、接口隔离原则
接口隔离原则
的核心思想在于,客户端不应该依赖于它不需要的接口。简单来说,接口隔离原则建议将大的、庞杂的接口拆分成多个小的、专注的接口,以减少类或模块对不必要方法的依赖。
当一个接口包含了多个方法时,可能会导致一些实现该接口的类,不得不实现它们不需要的方法。这会增加代码的复杂性,造成不必要的耦合,从而降低系统的灵活性和可维护性。
3.1、接口隔离原则反面案例
/*** 接口隔离原则* 现在有i1一个接口。它有B,C两个实现类* B和D实现了接口的所有方法* A通过接口使用B 但是A只会用到接口中的123方法* C通过接口使用D 但是C只会用到接口的145方法* 虽然A,C只会用到接口中的部分方法,但是B和D因为implement关键字的特性,必须被迫实现接口的所有方法*/
public class Demo1 {public static void main(String[] args) {A a = new A();a.depend1(new B());a.depend2(new B());a.depend3(new B());}
}interface I1{void method1();void method2();void method3();void method4();void method5();
}class B implements I1{@Overridepublic void method1() {System.out.println("B实现了I1的method1");}@Overridepublic void method2() {System.out.println("B实现了I1的method2");}@Overridepublic void method3() {System.out.println("B实现了I1的method3");}@Overridepublic void method4() {System.out.println("B实现了I1的method4");}@Overridepublic void method5() {System.out.println("B实现了I1的method5");}
}class D implements I1{@Overridepublic void method1() {System.out.println("D实现了I1的method1");}@Overridepublic void method2() {System.out.println("D实现了I1的method2");}@Overridepublic void method3() {System.out.println("D实现了I1的method3");}@Overridepublic void method4() {System.out.println("D实现了I1的method4");}@Overridepublic void method5() {System.out.println("D实现了I1的method5");}
}class A{public void depend1(I1 i1){i1.method1();}public void depend2(I1 i1){i1.method2();}public void depend3(I1 i1){i1.method3();}
}class C{public void depend1(I1 i1){i1.method1();}public void depend4(I1 i1){i1.method4();}public void depend5(I1 i1){i1.method5();}
}
3.2、接口隔离原则反面案例的改进
/***A通过接口使用B 但是A只会用到接口中的123方法 * C通过接口使用D 但是C只会用到接口的145方法* 就拆出三个接口,接口一只有1方法让B,D实现,接口二有2,3方法,让B实现,接口三有4,5方法,让D实现。* 即B和D无需实现多余的方法
**/
public class Demo2 {public static void main(String[] args) {A1 a1 = new A1();a1.depend1(new B1());
// a1.depend1(new D1());a1.depend3(new B1());a1.depend2(new B1());C1 c1 = new C1();c1.depend1(new D1());c1.depend4(new D1());c1.depend4(new D1());}
}interface Inter1{void method1();
}interface Inter2{void method2();void method3();
}interface Inter3{void method4();void method5();
}class B1 implements Inter1,Inter2{@Overridepublic void method1() {System.out.println("B实现了Inter1的method1");}@Overridepublic void method2() {System.out.println("B实现了Inter2的method2");}@Overridepublic void method3() {System.out.println("B实现了Inter2的method3");}
}class D1 implements Inter1,Inter3{@Overridepublic void method1() {System.out.println("D实现了Inter1的method1");}@Overridepublic void method4() {System.out.println("D实现了Inter3的method4");}@Overridepublic void method5() {System.out.println("D实现了Inter3的method5");}
}class A1{public void depend1(Inter1 inter1){inter1.method1();}public void depend2(Inter2 inter2){inter2.method2();}public void depend3(Inter2 inter2){inter2.method3();}
}class C1{public void depend1(Inter1 inter1){inter1.method1();}public void depend4(Inter3 inter3){inter3.method4();}public void depend5(Inter3 inter3){inter3.method5();}}
四、依赖倒转原则
依赖倒转原则
的核心思想在于面向接口
编程,即高层模块
不应该依赖低层模块
。两者都应该依赖抽象
。 抽象不应该依赖于细节。细节应该依赖于抽象。即高层模块和低层模块之间的依赖关系应该通过抽象(接口或抽象类)来连接。
这里不得不提到抽象类
或接口
的作用,简单地说,两者皆是一种规范
,作为模版,屏蔽了实现的细节。具体的实现都是交给子类去完成。
4.1、依赖倒转原则反面案例
在下面的案例中,发送邮件是一个具体的实现,用户在接受时也是接受了一个具体的实现。那么如果我现在不是发送邮件,而是需要发送短信或者微信呢?
那么就需要改动接收方的代码,将传入的Email
改成Message
或者WeChat
等。
public class Demo1 {public static void main(String[] args) {new Person().receive(new Email());}
}class Email{public String sendEmail(){return "发送邮件";}
}class Person{public void receive(Email email){System.out.println(email.sendEmail());}
}
4.1、依赖倒转原则反面案例的改进
在改进的代码中,选择将发送微信,短信,或者邮件的动作,抽象成一个Message
接口,在接受方法中,只需要传入Message
接口,调用接受方法时,传入该接口对应的实现即可,也是面向对象多态
特性的体现:
/*** 依赖倒转原则案例* 面向接口编程 只需要传递对应的实现类即可*/
public class Demo2 {public static void main(String[] args) {new Person().receive(new Email());new Person().receive(new Wechat());}
}interface Message{String sendMessage();
}class Email implements Message{@Overridepublic String sendMessage() {return "发送邮件";}
}class Wechat implements Message{@Overridepublic String sendMessage() {return "发送微信";}
}class Person{public void receive(Message message){System.out.println(message.sendMessage());}
}
五、里氏替换原则
里氏替换原则
的核心思想在于,要求子类能够完全替代父类使用,且不改变原有程序的正确性和行为。这意味着子类必须遵循父类定义的契约,确保在继承层次结构中,任何父类对象可以被子类对象所替换
,并且不会引发错误或改变系统行为。并且,子类应该在不破坏父类已有行为
的基础上,提供更多的功能,而不是改变父类的功能。
如果要满足该原则,就需要尽量不重写父类中的方法。从某种程度来说,是否失去了继承的意义?其实不然,里氏替换原则
只是告诉我们,不能滥用继承。里氏替换原则的核心目的是避免“强加不合理的行为”。即当你设计类层次结构时,应该确保父类的行为和子类的行为在语义上是一致的。就如最开始的案例一样,人可以继承人类去吃米饭,而猫不能继承人类去吃米饭,而应该吃猫粮。
5.1、里氏替换原则反面案例
/*** 里氏替换原则案例*/
public class Demo1 {public static void main(String[] args) {}
}class A{public int func1(int num1,int num2){return num1 - num2;}
}/*** B继承了A。无意中重写了func1方法,导致达不到预期的效果*/
class B extends A{@Overridepublic int func1(int num1, int num2) {return num1 + num2;}public int func2(int num1,int num2){return func1(num1,num2)+9;}
}
5.2、里氏替换原则反面案例的改进
/*** 里氏替换原则案例*/
public class Demo2 {public static void main(String[] args) {}
}/*** 将func1抽取到一个公共的接口中,哪个类需要用到func1,就自己实现接口去写自己的逻辑*/
interface Base{int func1(int num1,int num2);
}class A implements Base{@Overridepublic int func1(int num1,int num2){return num1 - num2;}
}/*** 如果B一定要用到A中的func1的逻辑,就使用组合的方式*/
class B implements Base{private A a = new A();@Overridepublic int func1(int num1, int num2) {return num1 + num2;}public int func2(int num1,int num2){return a.func1(num1,num2)+9;}
}
六、开闭原则
开闭原则
的核心思想在于,面对使用方
的修改关闭,面对提供方
的扩展开放,即:需求变化或新需求出现时,我们应该能够通过增加新的代码(如新的类或方法)来扩展系统的功能。现有的代码不应被修改,特别是已经经过测试并投入使用的部分。通过扩展而不是修改,避免破坏现有的功能,以及增加回归测试的成本
。
这一点在实际工作中深有体会,如果因为修改而破坏了原有的功能,以及修改一处导致其他位置出现问题,牵一发而动全身,只能是说明最初的设计存在问题,没有考虑完全。
6.1、开闭原则反面案例
/*** 测试开闭原则*/
public class Demo1 {public static void main(String[] args) {}
}/*** 如果这个时候又要加一个画其他图形的需求呢?* 那么需要改动if条件判断,还要加一个新方法*/
class GraphicEditor{public void drawShape(Shape s){if (s.type == 1){this.drawRectangle();}else if (s.type == 2){this.drawCircle();}}public void drawRectangle(){System.out.println("画矩形");}public void drawCircle(){System.out.println("画圆");}}class Shape{int type;
}class Rectangle extends Shape{public Rectangle(){super.type = 1;}
}class Circle extends Shape{public Circle(){super.type = 2;}
}
6.2、开闭原则反面案例的改进
实际上也是依赖倒转
原则的体现,利用接口或者抽象类作为中间层解耦。
/*** 测试开闭原则* 改进*/
public class Demo2 {public static void main(String[] args) {new Rectangle().draw();}
}/*** 将画图改造成抽象类,要画什么图形,就自己继承抽象类加上自己的逻辑即可*/
abstract class GraphicEditor{void draw(){}
}class Rectangle extends GraphicEditor{@Overridevoid draw() {System.out.println("画矩形");}
}class Circle extends GraphicEditor{@Overridevoid draw() {System.out.println("画圆形");}
}class Triangle extends GraphicEditor{@Overridevoid draw() {System.out.println("画三角形");}
}
七、迪米特原则
迪米特原则
的核心思想在于,和本类功能相关的代码,就应该尽量放在本类的相关方法中,而不是放在方法的调用方
。即调用方
不需要关心被调用方法的具体实现,这也是面向对象和面向过程的区别。即对象应该尽可能地少知道其他对象的内部实现或细节。
并且对象之间的交互应该尽量局限在直接的合作伙伴(即直接的成员变量、方法参数或者构造函数注入的对象)之间,而避免调用链过长的对象。
7.1、迪米特原则反面案例
/*** 演示迪米特法则*/
public class Demo1 {public static void main(String[] args) {SchoolManager schoolManager = new SchoolManager();schoolManager.printAll(new CollageManager());}
}class Employee{private String id;/*** 获取* @return id*/public String getId() {return id;}/*** 设置* @param id*/public void setId(String id) {this.id = id;}}class CollageEmployee{private String id;/*** 获取* @return id*/public String getId() {return id;}/*** 设置* @param id*/public void setId(String id) {this.id = id;}
}class CollageManager{public List<CollageEmployee> getAllCollageEmployee(){ArrayList<CollageEmployee> employeeEmployees = new ArrayList<>();for (int i = 0; i < 10; i++) {CollageEmployee employeeEmployee = new CollageEmployee();employeeEmployee.setId("学院员工id= "+i);employeeEmployees.add(employeeEmployee);}return employeeEmployees;}
}class SchoolManager{//CollageEmployee违反了迪米特原则,在printAll中,不关心CollageManager 是怎么把自己员工的信息打印出来的//应该把打印分公司员工的 信息 放到CollageManager类中public List<Employee> getAllEmployee(){ArrayList<Employee> employeeEmployees = new ArrayList<>();for (int i = 0; i < 5 ; i++) {Employee employeeEmployee = new Employee();employeeEmployee.setId("学校总部员工= "+i);employeeEmployees.add(employeeEmployee);}return employeeEmployees;}public void printAll(CollageManager collageManager){List<CollageEmployee> allCollageEmployee = collageManager.getAllCollageEmployee();System.out.println("分公司员工-------------");for (CollageEmployee c : allCollageEmployee) {System.out.println(c.getId());}List<Employee> allEmployee = this.getAllEmployee();System.out.println("总公司员工-------------");for (Employee employee : allEmployee) {System.out.println(employee.getId());}}
}
7.2、迪米特原则反面案例的改进
package com.light.principle.demeter.demo2;import java.util.ArrayList;
import java.util.List;/*** 演示迪米特法则*/
public class Demo2 {public static void main(String[] args) {SchoolManager schoolManager = new SchoolManager();schoolManager.printAll(new CollageManager());}
}class Employee{private String id;/*** 获取* @return id*/public String getId() {return id;}/*** 设置* @param id*/public void setId(String id) {this.id = id;}}class CollageEmployee{private String id;/*** 获取* @return id*/public String getId() {return id;}/*** 设置* @param id*/public void setId(String id) {this.id = id;}
}class CollageManager{public List<CollageEmployee> getAllCollageEmployee(){ArrayList<CollageEmployee> employeeEmployees = new ArrayList<>();for (int i = 0; i < 10; i++) {CollageEmployee employeeEmployee = new CollageEmployee();employeeEmployee.setId("学院员工id= "+i);employeeEmployees.add(employeeEmployee);}return employeeEmployees;}//把打印员工信息放回到CollageManager类中public void printCollageEmployee(){List<CollageEmployee> allCollageEmployee = this.getAllCollageEmployee();System.out.println("分公司员工-------------");for (CollageEmployee c : allCollageEmployee) {System.out.println(c.getId());}}
}class SchoolManager{public List<Employee> getAllEmployee(){ArrayList<Employee> employeeEmployees = new ArrayList<>();for (int i = 0; i < 5 ; i++) {Employee employeeEmployee = new Employee();employeeEmployee.setId("学校总部员工= "+i);employeeEmployees.add(employeeEmployee);}return employeeEmployees;}public void printAll(CollageManager collageManager){collageManager.printCollageEmployee();List<Employee> allEmployee = this.getAllEmployee();System.out.println("总公司员工-------------");for (Employee employee : allEmployee) {System.out.println(employee.getId());}}
}
八、合成复用原则
合成复用原则
实际上是对里氏替换原则
的一个总结,它的核心思想是:通过对象组合
(Composition)而不是继承
(Inheritance)来实现复用。在设计系统时,我们应该优先考虑将不同的功能或者行为封装成独立的对象,然后通过组合这些对象
来实现所需的功能,而不是通过继承关系来复用代码。
8.1、合成复用原则反面案例
class Bird {public void fly() {System.out.println("Flying");}public void eat() {System.out.println("Eating");}
}class Sparrow extends Bird {public void chirp() {System.out.println("Chirping");}
}class Penguin extends Bird {public void swim() {System.out.println("Swimming");}// 企鹅不应该飞行,但继承了 Bird,可能会误用 fly()@Overridepublic void fly() {throw new UnsupportedOperationException("Penguins can't fly");}
}
8.2、合成复用原则反面案例的改进
在改进案例中,将飞行和游泳拆分为了两个独立的接口,细化了各自的功能,实现类可以按需选择。
// 定义飞行行为接口
interface Flyable {void fly();
}// 定义游泳行为接口
interface Swimmable {void swim();
}// Bird 类只负责鸟类的通用行为
class Bird {public void eat() {System.out.println("Eating");}
}// 麻雀类通过实现 Flyable 实现飞行
class Sparrow extends Bird implements Flyable {public void fly() {System.out.println("Sparrow flying");}public void chirp() {System.out.println("Chirping");}
}// 企鹅类通过实现 Swimmable 实现游泳
class Penguin extends Bird implements Swimmable {public void swim() {System.out.println("Penguin swimming");}
}
从下一篇开始,对23种设计模式进行逐条解析。
相关文章:
设计模式の软件设计原则
文章目录 前言一、聚合&组合&继承&依赖1.1、继承1.2、组合1.3、聚合1.4、依赖 二、单一职责原则2.1、单一职责原则反面案例2.2、单一职责原则反面案例的改进 三、接口隔离原则3.1、接口隔离原则反面案例3.2、接口隔离原则反面案例的改进 四、依赖倒转原则4.1、依赖…...
【python自动化四】日志打印
我们在进行自动化测试时,需要打印过程日志和结果日志等,这里记录下日志的相关配置。这里我们直接自己新建一个logger。 先贴上日志代码如下,可根据需要修改: import logging import os import timefrom logging.handlers import …...
E498 ThinkPHP+MYSQL+LW+纯洁婚纱网站系统的设计与实现 源码 配置 文档 全套资料
婚纱网站系统的设计与实现 1.摘要2.开发目的和意义3.系统功能设计4.系统界面截图5.源码获取 1.摘要 在互联网和电子商务迅速发展的今天,网络已经是人们日常生活所不可缺少的信息获取渠道,人们日常生活基本已完全被网络所覆盖,互联网影响到各…...
【PostgreSQL系列】列类型从整数转换为 UUID
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
shell脚本实战案例
文章目录 实战第一坑功能说明脚本实现 实战第一坑 实战第一坑:在Windows系统写了一个脚本,比如上面,随后上传到服务,执行会报错 原因: 解决方案:在linux系统touch文件,并通过vim添加内容&…...
VAE为什么叫变分(variational),相对于AE有什么区别。
VAE为什么叫变分(variational),相对于AE有什么区别。 VAE为什么叫变分(variational)?VAE相对于AE有什么区别? VAE为什么叫变分(variational)? 变分自编码器&…...
Codeforces Round 991 (Div. 3)
补题连接 A. Line Breaks 思路:从头开始累加单词个数,超过m就退出。 代码: #include <bits/stdc.h> using namespace std; #define int long longvoid solve() {int n, m, k;cin >> n >> m;vector<string> a(n);…...
红日靶场vulnstark 4靶机的测试报告[细节](一)
目录 一、测试环境 1、系统环境 2、注意事项 3、使用工具/软件 二、测试目的 三、操作过程 1、信息搜集 2、漏洞利用Getshell ①Struts 2 s2-045漏洞 手工利用s2-45漏洞 Msf综合利用 ②Tomcat框架(CVE-2017-12615) ③phpMyAdmin(CVE-2018-12613) 构造语句写入冰蝎木…...
Android上运行OpenCV(Android Studio)
用Android Studio的话,整体来说没什么难的,照着教程来做就好了。 【OpenCV】OpenCV库的安装 - Android与OpenCV系列教程_哔哩哔哩_bilibili 主要就是导入module,然后加入依赖。代码只有几行。 if(OpenCVLoader.initLocal()){Toast.makeText(…...
代码随想录算法训练营day50|动态规划12
不同的子序列 给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。、 编辑距离中的删除元素,其实就是直接变数字,其只删除原来的较长的数组里的元素 递推模拟,使用s的最后一个元素匹配,或者删除…...
图像生成-扩散模型的经典之作DDPM
论文:https://arxiv.org/pdf/2006.11239 项目:https://github.com/hojonathanho/diffusion Denoising Diffusion Probabilistic Models (DDPM) 是一种生成模型,它通过一系列逐步添加噪声的过程将数据点映射到一个简单的先验分布(…...
知识拓展 ?. 连选链操作
?. 连选链操作 ?. 可选链操作符 ?. 是可选链操作符,常用于访问引用类型具有不确定性的内部数据时,比如要访问一个对象中的数组,不确定数组一定有数据就可以使用 ? 取读取它的 length 属性,如果对象没有这个属性也仅会返回 …...
API设计指南:详解HTTP状态码错误解析、HTTP方法及参数命名规则
目录 1、HTTP API规范1.1 原则1.2 协议1.3 版本1.4 路径1.5 HTTP 方法(Method)1.6 过滤信息1.7 参数命名1.8 HTTP 状态码(Response Code)1.9 鉴权 2、状态码2.1 API返回基础规范2.2 常见的 HTTP 状态码2.3 API错误信息应该放到响应…...
【D3.js in Action 3 精译_043】5.1 饼图和环形图的创建(三):圆弧的绘制
当前内容所在位置: 第五章 饼图布局与堆叠布局 ✔️ 5.1 饼图和环形图的创建 ✔️ 5.1.1 准备阶段(一)5.1.2 饼图布局生成器(二)5.1.3 圆弧的绘制(三) ✔️5.1.4 数据标签的添加(四&…...
7. 一分钟读懂“单例模式”
7.1 模式介绍 单例模式就像公司里的 打印机队列管理系统,无论有多少员工提交打印任务,大家的请求都汇总到唯一的打印管理中心,按顺序排队输出。这个中心必须全局唯一,避免多个队列出现资源冲突,保证打印任务井然有序。…...
如何让谷歌外链看起来更真实?
在SEO优化过程中,外链的自然性往往会被忽视,尤其是在一些急于见效的策略中,外链往往集中在高权重的少数几个网站上,导致外链结构单一且缺乏多样性。这样的外链网络容易让搜索引擎怀疑其真实性,进而影响网站排名。如何才…...
C标签和 EL表达式的在前端界面的应用
目录 前言 常用的c标签有: for循环 1 表示 普通的for循环的 2 常在集合中使用 表示 选择关系 1 简单的表示如果 2 表示如果。。否则。。 EL表达式 格式 : ${属性名/对象/ 集合} 前言 本篇博客介绍 c标签和el表达式的使用 使用C标签 要引入 …...
Luma 视频生成 API 对接说明
Luma 视频生成 API 对接说明 随着 AI 的应用变广,各类 AI 程序已逐渐普及。AI 已逐渐深入到人们的工作生活方方面面。而 AI 涉及的行业也越来越多,从最初的写作,到医疗教育,再到现在的视频。 Luma 是一个专业高质量的视频生成平…...
嵌入式基础:Linux C语言:Day7
重点: strlen()函数\strcpy()函数\strcat实现\strcmp()实现 数组的清空:bzero函数、memset函数 一、字符数组 <1> 概念 字符数组本质上就是一个数组,保存一个个字符,也一般用来保存字符串 字符串由多个字符组成的一个字符…...
阿里云盘permission denied
问题是执行 ./aliyunpan 时遇到了 Permission denied 的错误。这通常是因为文件没有执行权限。以下是解决问题的步骤: 检查文件权限 运行以下命令检查文件的权限: ls -l aliyunpan输出中会看到类似以下内容: -rw-r--r-- 1 user group 123…...
Flink学习连载文章12--FlinkSQL高级部分
eventTime 测试数据如下: {"username":"zs","price":20,"event_time":"2023-07-17 10:10:10"} {"username":"zs","price":15,"event_time":"2023-07-17 10:10:3…...
缓冲区溢出基础与实践
缓冲区溢出 缓冲区溢出是指当计算机向缓冲区内填充数据时超过了缓冲区本身的容量,溢出的数据覆盖在合法数据上。理想的情况是:程序检查数据长度并不允许输入超过缓冲区长度的字符,但是绝大多数程序都会假设数据长度总是与所分配的储存空间相匹…...
matlab figure函数 single 数据类型
1.matlab figure函数详细介绍 在MATLAB中,figure函数用于创建新的图形窗口或激活现有的图形窗口。以下是figure函数的详细介绍和用法: 基本用法 创建新图形窗口:不带任何参数调用figure会创建一个新的图形窗口,并将其设为当前活…...
量化交易系统开发-实时行情自动化交易-8.15.Ptrade/恒生平台
19年创业做过一年的量化交易但没有成功,作为交易系统的开发人员积累了一些经验,最近想重新研究交易系统,一边整理一边写出来一些思考供大家参考,也希望跟做量化的朋友有更多的交流和合作。 接下来会对于Ptrade/恒生平台介绍。 P…...
Vue03
目录 一、今日目标 1.生命周期 2.综合案例-小黑记账清单 3.工程化开发入门 4.综合案例-小兔仙首页 二、Vue生命周期 三、Vue生命周期钩子 四、生命周期钩子小案例 1.在created中发送数据 六、工程化开发模式和脚手架 1.开发Vue的两种方式 2.Vue CLI脚手架 基本介绍…...
【AI学习】Mamba学习(十九):关于S4-FouT
在前面《Mamba学习(十六):从S4到S5模型》一文中,提到了S4D-Lin,其具体状态矩阵A的初始化形式为: S4D-Lin对比S4D-Inv是一种更简单的形式,可以看作是对S4-FouT(S4的另外一种变体&am…...
YOLOv5-C3模块实现
YOLOv5-C3模块实现 🍨 本文为🔗365天深度学习训练营 中的学习记录博客 🍖 原作者:K同学啊 电脑系统:Windows11 显卡型号:NVIDIA Quadro P620 语言环境:python 3.9.7 编译器:jupyt…...
ubuntu下Qt5自动编译配置QtMqtt环境(10)
文章目录 [toc]1、概述2、下载QtMqtt源码3、编译4、验证5、参考6、视频 更多精彩内容👉内容导航 👈👉Qt网络编程 👈 1、概述 Qt默认是不包含mqtt库的,如果需要使用到mqtt库就只能自己编译配置; 网络所有的…...
切比雪夫不等式:方差约束下的概率估计
切比雪夫不等式:方差约束下的概率估计 背景 在概率分析中,切比雪夫不等式是一个常用的工具,它通过引入随机变量的 方差信息,给出了偏离均值的概率界限。这一不等式是对 马尔科夫不等式 的自然扩展,结合了更丰富的分布…...
SIP系列七:ICE框架(P2P通话)
我的音视频/流媒体开源项目(github) SIP系列目录 目录 一、NAT 1、NAT介绍 2、NAT类型 2.1、 完全圆锥型NAT 2.2、受限圆锥型NAT 2.3、端口受限圆锥型NAT 2.4、对称NAT 3、NAT打洞 3.1、不同一NAT下 3.2、同一NAT下 二、ICE 三、ICE中的SDP 至此&#x…...
小程序-基于java+SpringBoot+Vue的智慧校园管理系统设计与实现
项目运行 1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可 4.硬件环境:…...
Visual Studio 2022创建离线安装包
步骤1: 下载 Visual Studio 引导程序(最新版) 历史版本 步骤2 新建文件夹“E:\VS2022”,将下载的“vs_Professional.exe”拷贝到文件夹下在此文件夹窗口按住shift鼠标右键,选择“在此处打开powershell窗口” 步骤3 根据需要将代码复制到…...
Android 实现中英文切换
在开发海外项目的时候,需要实现app内部的中英文切换功能,所有的英文都是内置的,整体思路为: 创建一个sp对象,存储当前系统的语言类型,然后在BaseActivity中对语言进行判断; //公共Activitypubl…...
CmakeLists学习刨根问底
必要的两项内容 cmake_minimum_required(VERSION 2.5)project(mymuduo) 这行代码指定了构建项目所需的CMake最低版本为2.5。CMake是一个跨平台的自动化构建系统,它使用CMakeLists.txt文件来定义项目的构建过程。定义项目的名称为mymuduo。CMake将使用这个名称来生成…...
策略模式实战 - 猜拳游戏
**可以整体的替换一套算法,这就是策略模式。**这样对于同一个问题,可以有多种解决方案——算法实现的时候,可以通过策略模式来非常方便的进行算法的整体替换,而各种算法是独立封装好的,不用修改其内部逻辑。 具体的实…...
VoCo-LLaMA: Towards Vision Compression with Large Language Models
视觉语言模型在各种多模态任务上取得了显著的成功,但经常受到有限上下文窗口和处理高分辨率图像输入和视频的高计算成本的瓶颈。视觉压缩可以通过减少视觉令牌数量避免该问题。先前方法使用额外模块压缩视觉令牌并强制LLM理解压缩的令牌。然而,LLM对视觉…...
每日小知识
Kafka是一个分布式流平台,具有高性能、高可靠性和可扩展性的特点。它主要用于处理实时的数据流,将数据以高吞吐量的方式进行发布和订阅。以下是关于Kafka的几个基本概念和优势的介绍: 概念: 生产者(Producer…...
Linux其二设置端口号,静态ip以及命令
目录 1、VI编辑器 【linux版本的文本文件】 2) 补充的vi编辑器的其他内容(了解) 2、ln 连接的意思 link的缩写 3、文件的查看 【重点】 4、压缩与解压(重点) 5、find 查找命令 6、which & whereis 作用是一样的,表示某…...
吉林大学23级数据结构上机实验(第7周)
A 去火车站 寒假到了,小明准备坐火车回老家,现在他从学校出发去火车站,CC市去火车站有两种方式:轻轨和公交车。小明为了省钱,准备主要以乘坐公交为主。CC市还有一项优惠政策,持学生证可以免费乘坐一站轻轨&…...
SpringBoot(整合MyBatis + MyBatis-Plus + MyBatisX插件使用)
文章目录 1.整合MyBatis 1.需求分析2.数据库表设计3.数据库环境配置 1.新建maven项目2.pom.xml 引入依赖3.application.yml 配置数据源4.Application.java 编写启动类5.测试6.配置类切换druid数据源7.测试数据源是否成功切换 4.Mybatis基础配置 1.编写映射表的bean2.MonsterMap…...
【2024最新】基于Springboot+Vue的网上图书商城平台Lw+PPT
作者:计算机搬砖家 开发技术:SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等,“文末源码”。 专栏推荐:SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:Java精选实战项…...
JAVA-面向对象基础
文章目录 概要封装多态抽象类接口内部类为什么需要内部类 概要 面向对象是一种编程范式或设计哲学,它将软件系统设计为由多个对象组成,这些对象通过特定的方式相互作用 封装 将数据和操作数据的方法封装在一个类中,并通过访问修饰符控制对…...
Y3编辑器官方文档1:编辑器简介及菜单栏详解(文件、编辑、窗口、细节、调试)
文章目录 一、新建项目二、 编辑器主界面2.1 游戏场景2.2 导航栏/菜单栏2.3 功能栏三、菜单栏详细介绍3.1 文件3.1.1 版本管理3.1.2 项目管理(多关卡)3.1.2.1 多关卡功能说明3.1.2.2 关卡切换与关卡存档3.2 编辑3.2.1 通用设置3.2.2 键位设置3.3 窗口(日志)3.4 细节3.4.1 语言…...
力扣94题:二叉树的中序遍历
力扣94题:二叉树的中序遍历(C语言实现详解) 题目描述 给定一个二叉树的根节点 root ,返回它的中序遍历(Inorder Traversal)。 中序遍历的规则是: 先访问左子树;再访问根节点&…...
【数据结构】二叉树的性质和存储结构
性质 在二叉树的第i层上至多有2^{i-1}个结点,至少有1个结点 深度为k的二叉树至多有2^{k-1}个结点(k≥1),至少有k个结点 对任何一棵二叉树T,如果其叶子数为n0,度为2的结点数为n2,则n0n21 具有n个结点的完…...
【Spring项目】图书管理系统
阿华代码,不是逆风,就是我疯 你们的点赞收藏是我前进最大的动力!! 希望本文内容能够帮助到你!! 目录 一:项目实现准备 1:需求 (1)登录 2:准备…...
TCP编程案例
笔记:(本题可能需要的) TCP协议: TCP协议进行通信的两个应用进程:客户端、服务端。 使用TCP协议前,须先建立TCP连接,形成基于字节流的传输数据通道 传输前,采用“三次握手”方式…...
PyTorch 实现动态输入
使用 PyTorch 实现动态输入:支持训练和推理输入维度不一致的 CNN 和 LSTM/GRU 模型 在深度学习中,处理不同大小的输入数据是一个常见的挑战。许多实际应用需要模型能够灵活地处理可变长度的输入。本文将介绍如何使用 PyTorch 实现支持动态输入的 CNN 和…...
网络数据库
创建删除修改模式create schemadrop schema表create tabledrop tablealter table视图create view drop view索引create indexdrop index alter index 定义模式:create schema 《模式名》 authorization 《用户名》表定义语句 视图定义语句 授权定义语句//未指…...
【软考速通笔记】系统架构设计师⑲——专业英语
文章目录 一、前言二、常用名词三、架构风格四、非功能需求五、应用架构六、软件架构重用 一、前言 笔记目录大纲请查阅:【软考速通笔记】系统架构设计师——导读 二、常用名词 名词翻译architecture架构system系统design设计requirements需求components组件constr…...