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

【设计模式】SOLID设计原则

1、什么是SOLID设计原则

SOLID 是面向对象设计中的五个基本设计原则的首字母缩写,它们是:

单一职责原则(Single Responsibility Principle,SRP)
类应该只有一个单一的职责,即一个类应该有且只有一个改变的理由。这意味着一个类应该只负责一个特定的功能或任务,而不是多个不相关的功能。这样做可以提高类的内聚性,并使得类更容易理解、修改和测试。

开放-封闭原则(Open/Closed Principle,OCP)
软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。这意味着在不修改现有代码的情况下,应该能够通过添加新的代码来扩展系统的功能。这样做可以使得系统更加稳定,减少修改现有代码可能带来的风险。

里氏替换原则(Liskov Substitution Principle,LSP)
子类型必须能够替换其基类型。换句话说,任何可以接受基类型的地方都可以接受子类型,而且不会引发意外的行为。这样做可以保持系统的一致性和可靠性,并且确保使用继承时不会破坏代码的正确性。

接口隔离原则(Interface Segregation Principle,ISP)
客户端不应该被迫依赖于其不使用的接口。这意味着应该将接口设计成小而专注的接口,而不是大而臃肿的接口。这样做可以降低耦合性,并且使得系统更加灵活和易于维护。

依赖倒置原则(Dependency Inversion Principle,DIP)
高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。这样做可以降低模块之间的耦合度,并且使得系统更易于扩展和修改。

这些原则是由罗伯特·马丁(Robert C. Martin)等人在面向对象设计中提出的,它们提供了一套指导原则,帮助设计出高质量、可维护和可扩展的面向对象系统。

2、单一职责原则

单一职责原则(Single Responsibility Principle,SRP)要求一个类或模块应该只有一个单一的责任,即一个类或模块应该只负责一个特定的功能或任务。这样做可以提高代码的内聚性、可维护性和可测试性。

让我们通过一个简单的例子来说明单一职责原则:

假设我们有一个简单的应用程序,用于处理用户信息,包括保存用户信息到数据库和从数据库中检索用户信息。我们可以将这个功能拆分成两个类:一个负责保存用户信息,一个负责检索用户信息。

#include <iostream>
#include <string>// 负责保存用户信息到数据库
class UserSaver {
public:void saveUser(const std::string& username, const std::string& email) {// 将用户信息保存到数据库std::cout << "用户信息已保存到数据库:" << username << ", " << email << std::endl;}
};// 负责从数据库中检索用户信息
class UserRetriever {
public:void retrieveUser(const std::string& username) {// 从数据库中检索用户信息std::cout << "从数据库中检索到用户信息:" << username << std::endl;}
};int main() {UserSaver userSaver;userSaver.saveUser("Alice", "alice@example.com");UserRetriever userRetriever;userRetriever.retrieveUser("Alice");return 0;
}

在这个例子中,我们有两个类 UserSaverUserRetriever,它们分别负责保存用户信息和检索用户信息。这两个类各自都只有一个单一的职责,即负责一个特定的功能。如果我们需要修改保存用户信息的逻辑,我们只需要修改 UserSaver 类;如果我们需要修改检索用户信息的逻辑,我们只需要修改 UserRetriever 类。这样做提高了代码的可维护性,并且使得每个类更加简单和易于理解。

3、开放-封闭原则

开放-封闭原则(Open/Closed Principle,OCP)是面向对象设计中的一个基本原则,由柏拉图·梅特克斯(Bertrand Meyer)在他的《面向对象软件构造》(Object-Oriented Software Construction)一书中首次提出。它的核心思想是软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。换句话说,软件实体在不修改现有代码的情况下,应该能够通过添加新的代码来扩展系统的功能。

开放-封闭原则的目的是为了提高系统的可维护性、可扩展性和稳定性。通过遵循这一原则,可以使得系统更容易理解和修改,并且减少对现有代码的影响。

在实际应用中,可以通过以下几种方式来遵循开放-封闭原则:

抽象化:通过使用抽象类、接口或者抽象函数来定义可扩展的接口,从而使得系统可以根据需要进行扩展,而不必修改现有代码。

多态性:利用多态性和继承机制,使得系统可以通过添加新的子类来扩展功能,而不必修改基类或现有代码。

组合/聚合:通过组合或聚合关系来构建对象之间的关联关系,从而使得系统可以通过添加新的组件来扩展功能,而不必修改现有组件。

模块化:将系统分解成独立的模块或组件,使得每个模块只负责一个特定的功能,从而使得系统可以通过添加新的模块来扩展功能,而不必修改现有模块。

总之,开放-封闭原则指导我们设计出易于扩展和维护的软件系统,通过封装变化和利用多态性,使得系统可以根据需要进行扩展,而不必修改现有代码。

让我们通过一个简单的例子来说明开放-封闭原则。

假设我们有一个简单的图形绘制程序,它可以绘制不同形状的图形,包括圆形和矩形。现在我们希望在程序中添加新的图形类型,比如三角形。我们可以通过遵循开放-封闭原则来扩展程序的功能,而不必修改现有的代码。

首先,我们定义一个抽象基类 Shape,它有一个纯虚函数 draw 用于绘制图形:

#include <iostream>// 抽象基类:图形
class Shape {
public:virtual void draw() const = 0;
};

然后,我们定义具体的图形类,比如 CircleRectangle 类,它们分别继承自 Shape 类并实现 draw 函数:

// 圆形类
class Circle : public Shape {
public:void draw() const override {std::cout << "绘制圆形\n";}
};// 矩形类
class Rectangle : public Shape {
public:void draw() const override {std::cout << "绘制矩形\n";}
};

现在,如果我们想要添加新的图形类型,比如三角形,我们只需要添加一个新的类 Triangle,它也继承自 Shape 类并实现 draw 函数:

// 三角形类
class Triangle : public Shape {
public:void draw() const override {std::cout << "绘制三角形\n";}
};

通过这种方式,我们可以在不修改现有代码的情况下,通过添加新的类来扩展程序的功能,符合开放-封闭原则。这样做提高了代码的可维护性和可扩展性,使得系统更易于理解和修改。

4、 里氏替换原则

里氏替换原则(Liskov Substitution Principle,LSP)是面向对象设计中的一个基本原则,由芭芭拉·利斯科夫(Barbara Liskov)在 1987 年提出。该原则指出,子类型必须能够替换其基类型,即任何可以接受基类型的地方都可以接受子类型,而且不会引发意外的行为。

在更通俗的说法中,如果一个类型是子类型(派生类),那么它应该可以替换掉基类型(基类)并且不会破坏程序的正确性。换句话说,子类型应该保持基类型的行为,而不是产生意外的行为。

遵循里氏替换原则的目的是为了确保代码的一致性和可靠性,使得系统更易于理解、扩展和维护。如果违反了里氏替换原则,那么可能会导致程序的错误行为和不稳定性。

在实际应用中,可以通过以下几点来遵循里氏替换原则:

子类型必须实现基类型的所有行为,不能减少基类型的约束条件。
子类型可以增加新的行为,但不能修改基类型已有的行为。
子类型的前置条件(即输入条件)必须比基类型更宽松。
子类型的后置条件(即输出条件)必须比基类型更严格。

通过遵循里氏替换原则,可以确保系统的稳定性和可靠性,并且使得系统更易于扩展和维护。

让我们通过一个简单的例子来说明里氏替换原则。

假设我们有一个简单的几何图形类层次结构,包括基类 Shape 和两个子类 RectangleSquare,其中 SquareRectangle 的子类。

现在让我们来看看是否满足里氏替换原则:

#include <iostream>// 基类:图形
class Shape {
public:virtual void draw() const {std::cout << "绘制图形\n";}
};// 矩形类
class Rectangle : public Shape {
public:void draw() const override {std::cout << "绘制矩形\n";}
};// 正方形类
class Square : public Rectangle {
public:void draw() const override {std::cout << "绘制正方形\n";}
};// 绘制图形函数
void drawShape(const Shape& shape) {shape.draw();
}int main() {Rectangle rectangle;Square square;drawShape(rectangle); // 绘制矩形drawShape(square);    // 绘制正方形return 0;
}

在这个例子中,我们有一个基类 Shape,它有一个 draw 方法用于绘制图形。然后,我们有一个 Rectangle 类和一个 Square 类,它们分别继承自 Shape 类,并且都重写了 draw 方法以实现各自特定的绘制行为。

main 函数中,我们创建了一个 Rectangle 对象和一个 Square 对象,并且分别调用了 drawShape 函数来绘制这些图形。

在这个例子中,Square 类是 Rectangle 类的子类,符合继承关系。而且,在 drawShape 函数中,我们可以接受 Shape 类型的参数,并且传入 RectangleSquare 对象进行绘制,而不会产生意外的行为。

因此,这个例子满足了里氏替换原则:子类型(Square)可以替换其基类型(Rectangle)而不会引发意外的行为,程序的行为保持一致。

5、接口隔离原则

接口隔离原则(Interface Segregation Principle,ISP)是面向对象设计中的一个基本原则,由罗伯特·马丁(Robert C. Martin)在他的《敏捷软件开发:原则、模式和实践》(Agile Software Development, Principles, Patterns, and Practices)一书中提出。接口隔离原则指出,客户端不应该被迫依赖于其不使用的接口。换句话说,一个类不应该依赖于它不需要使用的接口,应该将接口设计成小而专注的接口,而不是大而臃肿的接口。

接口隔离原则的目的是为了提高系统的灵活性和可维护性。通过将接口拆分成小而专注的接口,可以降低类之间的耦合度,使得系统更易于理解、扩展和修改。同时,这也可以避免因为接口的臃肿而导致的功能耦合和代码冗余。

在实践中,可以通过以下几点来遵循接口隔离原则:

  1. 将大而臃肿的接口拆分成多个小而专注的接口,每个接口只包含一个单一的功能或职责。
  2. 只在需要使用某个接口的地方引入该接口,避免将不需要的接口强加给客户端。
  3. 根据客户端的需求,设计出合适的接口,并且保持接口的稳定性,避免频繁地修改接口。

通过遵循接口隔离原则,可以使得系统更灵活、更易于维护,并且能够更好地应对需求变化。

让我们通过一个简单的例子来说明接口隔离原则。

假设我们有一个简单的文件操作接口 FileOperation,它定义了一些文件操作的方法,比如打开文件、读取文件和关闭文件等。然后,我们有两个类 TextEditorImageEditor,它们分别实现了这个接口。

首先,让我们定义文件操作接口 FileOperation

#include <iostream>// 文件操作接口
class FileOperation {
public:virtual void open() = 0;virtual void read() = 0;virtual void close() = 0;
};

然后,我们有一个文本编辑器 TextEditor,它需要实现文件操作接口来打开和读取文本文件:

// 文本编辑器类
class TextEditor : public FileOperation {
public:void open() override {std::cout << "打开文本文件\n";}void read() override {std::cout << "读取文本文件\n";}void close() override {std::cout << "关闭文本文件\n";}
};

接着,我们有一个图像编辑器 ImageEditor,它也需要实现文件操作接口来打开和读取图像文件:

// 图像编辑器类
class ImageEditor : public FileOperation {
public:void open() override {std::cout << "打开图像文件\n";}void read() override {std::cout << "读取图像文件\n";}void close() override {std::cout << "关闭图像文件\n";}
};

在这个例子中,TextEditorImageEditor 都实现了 FileOperation 接口,但是它们只使用了其中的一部分方法(即打开和读取文件)。如果我们将所有文件操作都放在一个大的接口中,那么 TextEditorImageEditor 就不得不实现它们不需要的方法,违反了接口隔离原则。

通过将接口设计成小而专注的接口,每个接口只包含一个单一的功能或职责,我们遵循了接口隔离原则,并且使得系统更易于理解、扩展和修改。

6、依赖倒置原则

依赖倒置原则(Dependency Inversion Principle,DIP)是面向对象设计中的一个基本原则,由罗伯特·马丁(Robert C. Martin)在他的《敏捷软件开发:原则、模式和实践》(Agile Software Development, Principles, Patterns, and Practices)一书中提出。依赖倒置原则指出,高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。

依赖倒置原则的核心思想是通过使用抽象来降低类之间的耦合度,从而使得系统更加灵活、可扩展和易于维护。具体来说,依赖倒置原则要求我们将程序的设计重心放在抽象上,而不是具体实现上,通过使用接口、抽象类或者依赖注入等方式来实现依赖倒置。

在实践中,可以通过以下几点来遵循依赖倒置原则:

  1. 高层模块不应该依赖于低层模块,二者都应该依赖于抽象。即高层模块和低层模块都应该依赖于同一个抽象接口或抽象类。
  2. 抽象不应该依赖于具体实现,具体实现应该依赖于抽象。即抽象接口或抽象类不应该依赖于具体实现,而是具体实现应该依赖于抽象接口或抽象类。
  3. 可以通过依赖注入(Dependency Injection)等方式来实现依赖倒置,将具体实现的创建和注入交给外部,而不是在类内部创建具体实现的对象。

通过遵循依赖倒置原则,可以使得系统更加灵活、可扩展和易于维护,减少类之间的耦合度,提高代码的可复用性和可测试性。

让我们通过一个简单的例子来说明依赖倒置原则。

假设我们有一个简单的电子邮件发送系统,其中包含一个 EmailSender 类用于发送电子邮件。一开始,EmailSender 类直接依赖于具体的邮件服务提供商,比如 Gmail。这个设计违反了依赖倒置原则,因为高层模块 EmailSender 直接依赖于低层模块,即具体的邮件服务提供商。

#include <iostream>// 具体的邮件服务提供商:Gmail
class Gmail {
public:void sendEmail(const std::string& recipient, const std::string& message) {std::cout << "Sending email to " << recipient << " via Gmail: " << message << std::endl;}
};// 邮件发送类
class EmailSender {
private:Gmail gmail;public:void sendEmail(const std::string& recipient, const std::string& message) {gmail.sendEmail(recipient, message);}
};int main() {EmailSender sender;sender.sendEmail("example@example.com", "Hello, this is a test email.");return 0;
}

现在,让我们通过引入抽象来遵循依赖倒置原则。我们可以定义一个抽象的邮件服务接口 EmailService,并让 Gmail 类实现这个接口。然后,EmailSender 类只依赖于 EmailService 接口,而不是具体的邮件服务提供商。

#include <iostream>// 抽象的邮件服务接口
class EmailService {
public:virtual void sendEmail(const std::string& recipient, const std::string& message) = 0;
};// 具体的邮件服务提供商:Gmail
class Gmail : public EmailService {
public:void sendEmail(const std::string& recipient, const std::string& message) override {std::cout << "Sending email to " << recipient << " via Gmail: " << message << std::endl;}
};// 邮件发送类
class EmailSender {
private:EmailService* emailService;public:EmailSender(EmailService* service) : emailService(service) {}void sendEmail(const std::string& recipient, const std::string& message) {emailService->sendEmail(recipient, message);}
};int main() {Gmail gmail;EmailSender sender(&gmail);sender.sendEmail("example@example.com", "Hello, this is a test email.");return 0;
}

通过这种方式,EmailSender 类不再直接依赖于具体的邮件服务提供商,而是依赖于抽象的邮件服务接口 EmailService。这样做符合依赖倒置原则,使得系统更加灵活、可扩展和易于维护,因为现在可以轻松地切换不同的邮件服务提供商,而不需要修改 EmailSender 类的代码。

相关文章:

【设计模式】SOLID设计原则

1、什么是SOLID设计原则 SOLID 是面向对象设计中的五个基本设计原则的首字母缩写&#xff0c;它们是&#xff1a; 单一职责原则&#xff08;Single Responsibility Principle&#xff0c;SRP&#xff09;&#xff1a; 类应该只有一个单一的职责&#xff0c;即一个类应该有且只…...

基于java+springboot+vue实现的智能停车计费系统(文末源码+Lw+ppt)23-30

摘 要 随着人们生活水平的高速发展&#xff0c;智能停车计费信息管理方面在近年来呈直线上升&#xff0c;人们也了解到智能停车计费的实用性&#xff0c;因此智能停车计费的管理也逐年递增&#xff0c;智能停车计费信息的增加加大了在管理上的工作难度。为了能更好的维护智能…...

IntelliJ IDEA 2022.3.2 解决decompiled.class file bytecode version:52.0(java 8)

1 背景 使用idea 打开一个Kotlin语言编写的demo项目&#xff0c;该项目使用gradle构建。其gradle文件如下&#xff1a; plugins {id javaid org.jetbrains.kotlin.jvm version 1.8.20 } group me.administrator version 1.0-SNAPSHOTrepositories {mavenCentral()jcenter()…...

C++11 设计模式1. 模板方法(Template Method)模式学习。UML图

一 什么是 "模板方法&#xff08;Template Method&#xff09;模式" 在固定步骤确定的情况下&#xff0c;通过多态机制在多个子类中对每个步骤的细节进行差异化实现&#xff0c;这就是模板方法模式能够达到的效果。 模板方法模式属于&#xff1a;行为型模式。 二 &…...

HarmonyOS实战开发-自定义分享

介绍 自定义分享主要是发送方将文本&#xff0c;链接&#xff0c;图片三种类型分享给三方应用,同时能够在三方应用中展示。本示例使用数据请求 实现网络资源的获取&#xff0c;使用屏幕截屏 实现屏幕的截取&#xff0c;使用文件管理 实现对文件&#xff0c;文件目录的管理&…...

Spring源码刨析之配置文件的解析和bean的创建以及生命周期

public void test1(){XmlBeanFactory xmlBeanFactory new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));user u xmlBeanFactory.getBean("user",org.xhpcd.user.class);// System.out.println(u.getStu());}先介绍一个类XmlBeanFac…...

如何使用 Grafana 监控文件系统状态

当 JuiceFS 文件系统部署完成并投入生产环境&#xff0c;接下来就需要着手解决一个非常重要的问题 —— 如何实时监控它的运行状态&#xff1f;毕竟&#xff0c;它可能正在为关键的业务应用或容器工作负载提供持久化存储支持&#xff0c;任何小小的故障或性能下降都可能造成不利…...

智能革命:未来人工智能创业的天地

智能革命&#xff1a;未来人工智能创业的天地 一、引言 在这个数字化迅速变革的时代&#xff0c;人工智能(AI)已经从一个边缘科学发展成为推动未来经济和社会发展的关键动力。这一技术领域的飞速进步&#xff0c;不仅影响着科技行业的每一个角落&#xff0c;更是为创业者提供了…...

4月14日总结

java学习 一.多线程 简介&#xff1a;多线程是计算机科学中的一个重要概念&#xff0c;它允许程序同时执行多个任务或操作。在单个程序内部&#xff0c;多线程使得代码可以并行执行&#xff0c;从而提高程序的性能和响应速度。 这里先来介绍一下创建多线程的几种方法。 1.扩展…...

kafka---broker相关配置

一、Broker 相关配置 1、一般配置 broker.id 当前kafka服务的sid(server id)&#xff0c;在kafka集群中&#xff0c;该值是唯一的&#xff08;unique&#xff09;&#xff0c;如果未设置此值&#xff0c;kafka会自动生成一个int值&#xff1b;为了防止自动生成的值与用户设置…...

【Golang学习笔记】从零开始搭建一个Web框架(二)

文章目录 模块化路由前缀树路由 前情提示&#xff1a; 【Golang学习笔记】从零开始搭建一个Web框架&#xff08;一&#xff09;-CSDN博客 模块化路由 路由在kilon.go文件中导致路由和引擎交织在一起&#xff0c;如果要实现路由功能的拓展增强&#xff0c;那将会非常麻烦&…...

高精度地图导航论文汇总

文章目录 2021基于车载激光点云的高精地图矢量化成图[J] 2022基于高精度地图的智能车辆路径规划与跟踪控制研究[M] 2023一种无人驾驶融合决策方案的设计与实现[M] 2021 基于车载激光点云的高精地图矢量化成图[J] 摘要&#xff1a; 针对车载激光点云中对各特征物提取结果后矢量…...

【域适应】基于域分离网络的MNIST数据10分类典型方法实现

关于 大规模数据收集和注释的成本通常使得将机器学习算法应用于新任务或数据集变得异常昂贵。规避这一成本的一种方法是在合成数据上训练模型&#xff0c;其中自动提供注释。尽管它们很有吸引力&#xff0c;但此类模型通常无法从合成图像推广到真实图像&#xff0c;因此需要域…...

从零实现诗词GPT大模型:pytorch框架介绍

专栏规划: https://qibin.blog.csdn.net/article/details/137728228 因为咱们本系列文章主要基于深度学习框架pytorch进行,所以在正式开始之前,现对pytorch框架进行一个简单的介绍,主要面对深度学习或者pytorch还不熟悉的朋友。 一、安装pytorch 这一步很简单,主要通过p…...

[目标检测] OCR: 文字检测、文字识别、text spotter

概述 OCR技术存在两个步骤&#xff1a;文字检测和文字识别&#xff0c;而end-to-end完成这两个步骤的方法就是text spotter。 文字检测数据集摘要 daaset语言体量特色MTWI中英文20k源于网络图像&#xff0c;主要由合成图像&#xff0c;产品描述&#xff0c;网络广告(淘宝)MS…...

Windows环境下删除MySQL

文章目录 一、关闭MySQL服务1、winR打开运行&#xff0c;输入services.msc回车2、服务里找到MySQL并停止 二、卸载MySQL软件1、打开控制模板--卸载程序--卸载MySQL相关的所有组件 三、删除MySQL在物理硬盘上的所有文件1、删除MySQL的安装目录&#xff08;默认在C盘下的Program …...

uniapp:uview-plus的一些记录

customStyle 并不是所有的组件都有customStyle属性来设置自定义属性&#xff0c;有的还是需要通过::v-deep来修改内置样式 form表单 labelStyle 需要的是一个对象 :labelStyle"{color: #333333,fontSize: 32rpx,fontWeight: 500}"dateTimePicker选择器设置默认值…...

OLTP 与 OLAP 系统说明对比和大数据经典架构 Lambda 和 Kappa 说明对比——解读大数据架构(五)

文章目录 前言OLTP 和 OLAPSMP 和 MPPlambda 架构Kappa 架构 前言 本文我们将研究不同类型的大数据架构设计&#xff0c;将讨论 OLTP 和 OLAP 的系统设计&#xff0c;以及有效处理数据的策略包括 SMP 和 MPP 等概念。然后我们将了解经典的 Lambda 架构和 Kappa 架构。 OLTP …...

步骤大全:网站建设3个基本流程详解

一.领取一个免费域名和SSL证书&#xff0c;和CDN 1.打开网站链接&#xff1a;https://www.rainyun.com/z22_ 2.在网站主页上&#xff0c;您会看到一个"登陆/注册"的选项。 3.点击"登陆/注册"&#xff0c;然后选择"微信登录"选项。 4.使用您的…...

利用Sentinel解决雪崩问题(二)隔离和降级

前言&#xff1a; 虽然限流可以尽量避免因高并发而引起的服务故障&#xff0c;但服务还会因为其它原因而故障。而要将这些故障控制在一定范围避免雪崩&#xff0c;就要靠线程隔离(舱壁模式)和熔断降级手段了&#xff0c;不管是线程隔离还是熔断降级&#xff0c;都是对客户端(调…...

基于springboot的房产销售系统源码数据库

基于springboot的房产销售系统源码数据库 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于房产销售系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了房产…...

【MATLAB】基于Wi-Fi指纹匹配的室内定位-仿真获取WiFi RSSI数据(附代码)

基于Wi-Fi指纹匹配的室内定位-仿真获取WiFi RSSI数据 WiFi指纹匹配是室内定位最为基础和常见的研究&#xff0c;但是WiFi指纹的采集可以称得上是labor-intensive和time-consuming。现在&#xff0c;给大家分享一下我们课题组之前在做WiFi指纹定位时的基于射线跟踪技术仿真WiFi…...

深圳晶彩智能ESP32-3248S035R使用LovyanGFX实现手写板

深圳晶彩智能ESP32-3248S035R介绍 深圳晶彩智能出品ESP32-3248S035R为3.5寸彩色屏采用分辨率480x320彩色液晶屏&#xff0c;驱动芯片是ST7796。板载乐鑫公司出品ESP-WROOM-32&#xff0c;Flash 4M。型号尾部“R”标识电阻膜的感压式触摸屏&#xff0c;驱动芯片是XPT2046。 Lo…...

【Spring Boot】深入解密Spring Boot日志:最佳实践与策略解析

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录文章&#xff1a;【Spring Boot】深入解密Spring Boot日志&#xff1a;最佳实践与策略解析 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 Spring Boot 日志一. 日志的概念?…...

ISTQB选择国内版,还是国际版呢

1, ISTQB简介 ISTQB&#xff08;International Software Testing Qualifications Board&#xff09;是一个国际软件测试资格认证机构&#xff0c;旨在提供一个统一的软件测试认证标准。ISTQB成立于2002年&#xff0c;是非盈利性的组织&#xff0c;由世界各地的国家或地区软件测…...

头歌-机器学习 第11次实验 softmax回归

第1关&#xff1a;softmax回归原理 任务描述 本关任务&#xff1a;使用Python实现softmax函数。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.softmax回归原理&#xff0c;2.softmax函数。 softmax回归原理 与逻辑回归一样&#xff0c;softmax回归同样…...

Qt for MCUs 2.7正式发布

本文翻译自&#xff1a;Qt for MCUs 2.7 released 原文作者&#xff1a;Qt Group高级产品经理Yoann Lopes 翻译&#xff1a;Macsen Wang Qt for MCUs的新版本已发布&#xff0c;为Qt Quick Ultralite引擎带来了新功能&#xff0c;增加了更多MCU平台的支持&#xff0c;并且我们…...

共享IP和独享IP如何选择,两者有何区别?

有跨境用户在选择共享IP和独享IP时会有疑问&#xff0c;不知道该如何进行选择&#xff0c;共享IP和独享IP各有其特点和应用场景&#xff0c;选择哪种方式主要取决于具体需求和预算。以下是对两者的详细比较&#xff1a; 首先两者的主要区别在于使用方式和安全性&#xff1a;共…...

文心一言VSchatGPT4

文心一言和GPT-4各有优势&#xff0c;具体表现在不同的测试场景下。 在某些测试场景中心一言的表现优于GPT-4&#xff0c;例如在故事的完整度和情节吸引力方面&#xff0c;文心一言表现得更加符合指令&#xff0c;情节更吸引人。这可能得益于其模型在训练时对中文语境的深入理…...

Linux 目录结构与基础查看命令

介绍 目录结构如下 /bin&#xff1a;存放着用户最经常使用的二进制可执行命令&#xff0c;如cp、ls、cat等。这些命令是系统管理员和普通用户进行日常操作所必需的。 /boot&#xff1a;存放启动系统使用的一些核心文件&#xff0c;如引导加载器&#xff08;bootstrap loader…...

网站建设 千佳网络/阿里云域名查询和注册

题目链接 AtCoder&#xff1a;https://agc010.contest.atcoder.jp/tasks/agc010_c 洛谷&#xff1a;https://www.luogu.org/problemnew/show/AT2304 Solution 窝yy了好久的dpQAQ 标算很巧妙&#xff1a;我们考虑算每条边被经过了多少次&#xff0c;这里把一个叶子节点到另一个叶…...

网站备案证明/网络推广外包怎么接单

PHP程序使用mail()函数发送邮件的时候&#xff0c;标题中文的话会出现乱码。 解决方法&#xff1a; 先用函数base64_encode() — 使用 MIME base64 对数据进行编码 标题字符串前加编码类型例如&#xff1a; ?UTF-8?B? 标题字符串后加&#xff1a;? 邮件header说明Content-t…...

ASPnet动态网站开发教程试卷/株洲企业seo优化

第一次见到iRobot创始人Colin Angle&#xff0c;看到的是他很有礼貌的微笑&#xff0c;以及经过前几轮采访后的浅浅倦意。此次来到中国&#xff0c;Colin Angle的任务是将此前在美国已经亮相的iRobot扫地机器人新品Roomba i7带到中国。在全程一个多小时的交流过程中&#xff0c…...

丹徒网站建设价格/个人怎么做免费百度推广

重构&#xff1a;改变既有代码的一剂良药 1. 什么是系统重构&#xff1f; 它是一套严谨而安全的过程方法&#xff0c;它通过一系列行之有效的方法与措施&#xff0c;保证软件在优化的同时&#xff0c;不会引入新的bug,保证软件改造的质量。 2. 系统重构的概念 系统重构&#xf…...

资源分享类网站模板/建网站软件工具

“他们家产品之间的快捷键统一&#xff0c;切换起来无门槛&#xff1b;” 用三个字描述这句话&#xff1f; 三字&#xff1a;“单一化”OR“统一性” 而JetBrains的工具恰恰与上述大头们背道而驰。他只做一类很窄的人群&#xff08;相对于二八法则来说&#xff0c;傻瓜式操作的…...

做网站vi系统是什么/合肥百度搜索优化

免费自动化测试软件 AlldayTest下载地址为&#xff1a; http://www.alldaytest.com/download.do?lancn 绿色免费版下载地址华军软件园也有AlldayTest兼具功能测试和性能测试&#xff0c;支持测试Web(html,ASP,JSP,PHP等),C#,VB,C,Activex,Silverlight,WPF等多种编程语言编写的…...