软件设计原则 1小时系列 (C++版)
文章目录
- 前言
- 基本概念
- Design Principles
- ⭐单一职责原则
- (SRP) Single Responsibility Principle
- Code
- ⭐里氏替换原则
- (LSP) Liskov Substitution Principle
- Code
- ⭐开闭原则
- (OCP) Open Closed Principle
- Code
- ⭐依赖倒置原则
- (DIP) Dependency Inversion Principle
- Code
- ⭐接口隔离原则
- (ISP) Interface Segregation Principle
- Code
- ⭐迪米特法则
- (LOD) Law of Demeter
- 无具体Code
- ⭐合成复用原则
- (CRP) Composite Reuse Principle
- Code
- END
- 设计模式 李建忠 C++
- 敏捷软件开发 - 面向对象设计的原则
前言
申明:
原视频:
面向对象-软件设计原则-1小时搞懂-波波酱老师_哔哩哔哩_bilibili
本文为up主的视频教学总结成文本和code
业主要是为了Cpper学习者学习。因为up在视频中使用的是java描述。
基本概念
-
📌可维护性质
在不破坏原有代码设计,不要引入新bug的情况下,能够快速修改或者添加代码
生活案例:比如一个iPhone在维修摄像头的时候,如果一个手抖,就可能呆滞喇叭或者麦克风损坏,从而影响了通讯或者音视频功能,因为它们都集成在一个电路板上。但是,单反在维修的时候,就不存在这种情况‘
-
📌可扩展性
在不修改或者少量修改原有代码的情况下,可以通过扩展的方式添加新的功能代码
生活案例:中秋到了,拿着iPhone想要拍个月亮发朋友圈,但是不管怎么拍,效果都不好。这个时候,只见隔壁老王把单发装在三脚架上,然后换上长焦镜头,“咔嚓”一声,我凑过去一看,“哇,真的是又大又圆啊!”。这个时候,单反可以根据不同的拍摄场景,扩展不同的镜头。
-
📌可复用性
尽量减少代码的重复编写,直接复用已有的代码
生活案例:开发教务系统的时候,直接复用权限管理模块
-
📌内聚性
模块内部元素的紧密程度,内聚性越高,那么模块独立性越好,可维护性,复用性也越高
-
📌耦合性
模块与模块之间的关联关系,耦合度越高,那么模块与模块之间的关联越复杂,那么可维护性,复用性越差
Design Principles
⭐单一职责原则
(SRP) Single Responsibility Principle
一个类或者模块只负责完成一个职责(或者功能)。
通俗的讲,如果这个类包含两个或者多个不相干的功能,那么这个类的职责就不够单一,应该将它拆分成多个功能更加单一,粒度更细的类。
单一职责原则是实现高内聚,低耦合的指导方针,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关实现经验。
Code

old
#include <iostream>
#include <string>class UserInfo {
private:long userID;std::string userName;std::string phone;std::string province;std::string city;std::string region;std::string detailAddress;public:void save() {std::cout << "save user information" << std::endl;}void saveAddress() {std::cout << "save address information" << std::endl;}
};
new
#include <iostream>
#include <list>
#include <string>class Address {
private:std::string city;std::string region;std::string detailAddress;public:void saveAddress() {std::cout << "save address information" << std::endl;}
};class UserInfo {
private:long userID;std::string userName;std::string phone;std::string province;std::list<Address> addressList;public:void save() {std::cout << "save user information" << std::endl;}
};
⭐里氏替换原则
(LSP) Liskov Substitution Principle
子类对象能够替换程序中父类对象出现的任何地方,并且保证原来程序的瑞吉行为不变及正确性不被破快。
通俗理解:子类可以扩展父类的功能,但不改变父类原有的功能。
换句话说,子类继承父类时,除添加新的方法完成新功能外,尽量不要重写父类的方法,如果重写父类方法,程序运行会发生出错概率。
如果一定要用多态,那么父类可以设计成抽象父类或者接口。
Code

old
#include <iostream>// 接口过于庞大
class PhoneFunction {
public:virtual void call() = 0;virtual void message() = 0;virtual void camera() = 0;
};class ApplePhone : public PhoneFunction {
public:virtual void call() override {std::cout << "Apple " << __func__ << std::endl;}virtual void message() override {std::cout << "Apple " << __func__ << std::endl;}virtual void camera() override {std::cout << "Apple " << __func__ << std::endl;}
};class OldPhone : public PhoneFunction {
public:virtual void call() override {std::cout << "Old " << __func__ << std::endl;}virtual void message() override {std::cout << "Old " << __func__ << std::endl;}virtual void camera() override {std::cout << "Old " << __func__ << std::endl;}
};
new
#include <iostream>// 接口粒度最小
struct Call {virtual void call() = 0;
};struct Message {virtual void message() = 0;
};struct Camera {virtual void camera() = 0;
};class ApplePhone : public Call, public Message, public Camera {
public:virtual void call() override {std::cout << "Apple " << __func__ << std::endl;}virtual void message() override {std::cout << "Apple " << __func__ << std::endl;}virtual void camera() override {std::cout << "Apple " << __func__ << std::endl;}
};class OldPhone : public Call, public Message {
public:virtual void call() override {std::cout << "Old " << __func__ << std::endl;}virtual void message() override {std::cout << "Old " << __func__ << std::endl;}
};
⭐开闭原则
(OCP) Open Closed Principle
对扩展开放,对修改关闭。
在程序需要进行拓展的时候,不要去修改原有代码,实现一个热拔插的效果。
简而言之,是为了使程序的扩展性好,易于维护与升级。
想要达到这样的效果,我们需要使用接口和抽象类。
因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。
而软件中异变的细节可以从抽象派生的实现类来进行扩展,当软件需要发生变化时,只需要根据需求派生一个实现类来扩展就可以了。
Code

old
#include <ctime>
#include <iostream>
#include <string>class Equation {
protected:int leftNum;int rightNum;int result;std::string op;public:std::string toString() {return std::to_string(leftNum) + op + std::to_string(rightNum) + "=" +std::to_string(result);}int generateRandom(int min, int max) {return rand() % (max - min + 1) + min;}Equation generateEquation(std::string op) {leftNum = generateRandom(0, 100);rightNum = generateRandom(0, 100);if (op == "+") {result = leftNum + rightNum;} else if (op == "-") {result = leftNum - rightNum;}this->op = op;return *this;}
};int main() {srand(time(0));Equation equation = Equation().generateEquation("-");std::cout << equation.toString() << std::endl;
}
new
#include <ctime>
#include <iostream>
#include <string>class Equation {
protected:int leftNum;int rightNum;int result;std::string op;public:std::string toString() {return std::to_string(leftNum) + op + std::to_string(rightNum) + "=" +std::to_string(result);}int generateRandom(int min, int max) {return rand() % (max - min + 1) + min;}// 抽象方法// 注意,C++中,抽象基类无法实例化,因此无法直接返回`Equation`virtual Equation* generateEquation() = 0;
};class AddEquation : public Equation {
public:Equation* generateEquation() override {leftNum = generateRandom(0, 100);rightNum = generateRandom(0, 100);result = leftNum + rightNum;this->op = "+";return this;}
};class SubEquation : public Equation {
public:Equation* generateEquation() override {leftNum = generateRandom(0, 100);rightNum = generateRandom(0, 100);result = leftNum - rightNum;this->op = "-";return this;}
};int main() {srand(time(0));// 多态Equation* equation = (new SubEquation())->generateEquation();std::cout << equation->toString() << std::endl;delete equation;equation = (new AddEquation())->generateEquation();std::cout << equation->toString() << std::endl;delete equation;
}
⭐依赖倒置原则
(DIP) Dependency Inversion Principle
模块之间要依赖抽象,不依赖实现,要面向接口编程,不要面向实现编程。
高层模块不应该直接依赖底层模块,这样就降低了客户端与实现模块间的耦合。
Code

old
#include <iostream>class IntelCpu {
public:void calculate() {std::cout << "IntelCpu " << __func__ << std::endl;}
};class IntelMemory {
public:void storage() {std::cout << "IntelMemory " << __func__ << std::endl;}
};class Computer {
private:IntelCpu intelCpu;IntelMemory intelMemory;public:Computer() {}Computer(IntelCpu intelCpu, IntelMemory intelMemory) {this->intelCpu = intelCpu;this->intelMemory = intelMemory;}void startRun() {intelCpu.calculate();intelMemory.storage();}
};int main() {IntelCpu intelCpu;IntelMemory intelMemory;Computer computer(intelCpu, intelMemory);computer.startRun();
}

new
#include <iostream>class Cup {
public:virtual void calculate() = 0;
};class Memory {
public:virtual void storage() = 0;
};class IntelCpu : public Cup {
public:void calculate() override {std::cout << "IntelCpu " << __func__ << std::endl;}
};class IntelMemory : public Memory {
public:void storage() override {std::cout << "IntelMemory " << __func__ << std::endl;}
};class AmdCpu : public Cup {
public:void calculate() override {std::cout << "AmdCpu " << __func__ << std::endl;}
};class AmdMemory : public Memory {
public:void storage() override {std::cout << "AmdMemory " << __func__ << std::endl;}
};class Computer {
private:Cup* cpu;Memory* memory;public:Computer() {}Computer(Cup* cpu, Memory* memory) {this->cpu = cpu;this->memory = memory;}void startRun() {cpu->calculate();memory->storage();}
};int main() {Computer computer;IntelCpu intelCpu;IntelMemory intelMemory;computer = Computer(&intelCpu, &intelMemory);computer.startRun();AmdCpu amdCpu;AmdMemory amdMemory;computer = Computer(&amdCpu, &amdMemory);computer.startRun();
}
⭐接口隔离原则
(ISP) Interface Segregation Principle
客户端不应该被迫依赖于它不适用的方法,一个类对于另一个类的依赖应该建立在最小的接口上。
一个类实现一个接口,就必须实现这个接口的所有抽象方法,如果接口的设计过于庞大的话,实现类就被迫实现不需要的抽象方法。
Code

old
#include <iostream>class Bird {
protected:double runSpeed;double flySpeed;public:virtual void setRunSpeed(double runSpeed) {this->runSpeed = runSpeed;}virtual void setFlySpeed(double flySpeed) {this->flySpeed = flySpeed;}double calcFlyTime(double distance) {return distance / flySpeed;}double calcRunTime(double distance) {return distance / runSpeed;}
};class Parrot : public Bird {
public:void studySpeak() {std::cout << __func__ << std::endl;}
};class Ostrich : public Bird {
public:virtual void setFlySpeed(double flySpeed) override {this->flySpeed = 0;}
};int main() {Bird* parrot = new Parrot();parrot->setFlySpeed(150.0);std::cout << "fly 300km" << std::endl;std::cout << "parrot uses " << parrot->calcFlyTime(300.0) << " hours"<< std::endl;Bird* ostrich = new Ostrich();ostrich->setFlySpeed(150.0);std::cout << "fly 300km" << std::endl;std::cout << "ostrich uses " << ostrich->calcFlyTime(300.0) << " hours"<< std::endl;
}

new
#include <iostream>class Bird {
protected:double runSpeed;double flySpeed;public:virtual void setRunSpeed(double runSpeed) {this->runSpeed = runSpeed;}virtual void setFlySpeed(double flySpeed) {this->flySpeed = flySpeed;}double calcFlyTime(double distance) {return distance / flySpeed;}double calcRunTime(double distance) {return distance / runSpeed;}
};class Parrot : public Bird {
public:void studySpeak() {std::cout << __func__ << std::endl;}
};class Ostrich : public Bird {
public:virtual void setFlySpeed(double flySpeed) override {this->flySpeed = 0;}
};int main() {Bird* parrot = new Parrot();parrot->setFlySpeed(150.0);std::cout << "fly 300km" << std::endl;std::cout << "parrot uses " << parrot->calcFlyTime(300.0) << " hours"<< std::endl;Bird* ostrich = new Ostrich();ostrich->setFlySpeed(150.0);std::cout << "fly 300km" << std::endl;std::cout << "ostrich uses " << ostrich->calcFlyTime(300.0) << " hours"<< std::endl;
}
⭐迪米特法则
(LOD) Law of Demeter
迪米特法则来自于1987年美国东北大学的一个名为Demeter的一个项目,只跟朋友联系,不跟“陌生人”说话。
如果两个软件实体无须直接通信,那么就不应该发生直接的互相调用,可以通过第三方转发该调用。
其目的是降低类之间的耦合度,提高模块的相对独立性。
无具体Code
无具体code
这个发展在项目中的各个模块调用非常之多,需要多项目,业务非常熟悉才能搭建良好的结构。


⭐合成复用原则
(CRP) Composite Reuse Principle
尽量先适用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
通常类的复用分为继承复用和合成复用两种。
继承复用虽然简单和易实现的优点,但它也存在以下缺点:
- 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为”白箱“复用。
- 子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展和维护。
采用组合或聚合复用时,可以将已有的对象纳入新对象中,使之成功新对象的一部分,新对象可以调用已有对象的功能,它有以下优点:
- 它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称”黑箱“复用。
- 对象间的耦合度低。可以在类的成员位置声明抽象(抽象类或者接口)
Code


old
#include <iostream>
#include <string>class A {
protected:std::string name;int age;public:void methodA() {std::cout << "A " << __func__ << std::endl;}
};class B : public A {
public:void methodB() {std::cout << "B " << __func__ << std::endl;}
};int main() {B b;b.methodA();b.methodB();
}
new
#include <iostream>
#include <string>class A {
protected:std::string name;int age;public:void methodA() {std::cout << "A " << __func__ << std::endl;}
};class B : public A {
public:void methodB() {std::cout << "B " << __func__ << std::endl;}
};int main() {B b;b.methodA();b.methodB();
}
END
设计模式 李建忠 C++
设计模式 李建忠 C++
敏捷软件开发 - 面向对象设计的原则
在敏捷软件开发中提出了以下设计原则
SRP 单一职责原则
就一个类而言,应该仅有一个引起它变化的原因
OCP 开放封闭原则
软件实体(类、模块、函数等)应该是可以扩展的,但是不可修改
LSP Liskov替换原则
子类型必须能替换换他们的基本类型
DIP 依赖倒置原则
抽象不应该依赖细节。细节应该依赖于抽象。
ISP 接口隔离原则
不应该强迫客户依赖于他们不用的方法。接口属于客户,不属于他所在的类层次结构。
REP 重用发布等价原则
重用的粒度就是发布的粒度
CCP 共用重用原则
一个包中的所有类应该是共用重用的。如果重用了包中的一个类,那么就重用包中的所有类。互相之间没有紧密联系的类不应该在同一个包中。
CRP 共用封闭原则
一个包中的所有类对于同一个类性质的变化应该是共同封闭的。一个变化若对一个包影响,则将对包中的所有类产生影响,而对其他的包不造成任何影响。
ADP 无依赖原则
在包的依赖关系中不存在环。细节不应该被依赖。
SDP 稳定依赖原则
朝着稳定的方向依赖。
ASP 稳定抽象原则
一个包的抽象程度应该和其他稳定程度一致。
相关文章:
软件设计原则 1小时系列 (C++版)
文章目录 前言基本概念 Design Principles⭐单一职责原则(SRP) Single Responsibility PrincipleCode ⭐里氏替换原则(LSP) Liskov Substitution PrincipleCode ⭐开闭原则(OCP) Open Closed PrincipleCode ⭐依赖倒置原则(DIP) Dependency Inversion PrincipleCode ⭐接口隔离…...
数据结构--》解锁数据结构中树与二叉树的奥秘(一)
数据结构中的树与二叉树,是在建立非线性数据结构方面极为重要的两个概念。它们不仅能够模拟出生活中各种实际问题的复杂关系,还常被用于实现搜索、排序、查找等算法,甚至成为一些大型软件和系统中的基础设施。 无论你是初学者还是进阶者&…...
23.4 Bootstrap 框架5
1. 背景颜色 1.1 背景颜色样式 在Bootstrap 5中, 可以使用以下类来设置背景颜色: * 1. .bg-primary: 设置为主要的背景颜色(#007bff, 深蓝色). * 2. .bg-secondary: 设置为次要的背景颜色(#6c757d, 灰色). * 3. .bg-success: 设置为成功的背景颜色(#28a745, 绿色). * 4. …...
Spring源码解析——IOC属性填充
正文 doCreateBean() 主要用于完成 bean 的创建和初始化工作,我们可以将其分为四个过程: 最全面的Java面试网站 createBeanInstance() 实例化 beanpopulateBean() 属性填充循环依赖的处理initializeBean() 初始化 bean 第一个过程实例化 bean在前面一篇…...
寒露到了,冬天还会远吗?
寒露惊秋晚,朝看菊渐黄。 日复一日间,光影如梭,我们便很快将告别了秋高气爽,白日将变得幽晦, 天寒夜长,风气萧索,雾结烟愁。 还没好好体会秋高气爽,寒露就到了。 今天晚上9点多,我们…...
科普②| 大数据有什么用?大数据技术的应用领域有哪些?
1、提供个性服务很多人觉得大数据好像离我们很远,其实我们在日常所使用的智能设备,就需要大数据的帮助。比如说我们运动时候戴的运动手表或者是运动手环,就可以在我们平时运动的时候,帮助我们采集运动数据及热量消耗情况。进入睡眠…...
golang的切片使用总结二
如果没看golang切片的第一篇总结博客 golang的切片使用总结一-CSDN博客 ,请浏览之 举例9:make([]int, a, b)后访问下标a的元素 s : make([]int, 10, 12) v : s[10] fmt.Printf("v:%v", v) 打印结果: panic: runtime error: index …...
tailscale自建headscale和derp中继
tailscale derp中继服务简介 tailscale是一个基于WireGuard的零配置软件,它可以轻松地在多台设备之间建立点对点加密连接。 derp服务器是tailscale网络的重要组成部分。它作为tailscale客户端之间的中继,帮助客户端找到并连接到其他客户端设备。 但Tailscale 官方…...
布隆过滤器的使用
布隆过滤器简介 Bloom Filter(布隆过滤器)是一种多哈希函数映射的快速查找算法。它是一种空间高效的概率型数据结构,通常应用在一些需要快速判断某个元素是否属于集合,但是并不严格要求100%正确的场合。 布隆过滤器的优势在于,利用很少的空…...
Web开发-单例模式
目录 单例模式介绍代码实现单例模式 单例模式介绍 单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点。单例模式可以通过private属性实现。通过将类的构造函数设为private,可以防止类在外部被实例化。单例模式通…...
MySQL:温备份和恢复-mysqldump (4)
介绍 温备:同样是在数据库运行的时候进行备份的,但对当前数据库的操作会产生影响。(只可以读操作,不可以写操作) 温备份的优点: 1.可在表空间或数据文件级备份,备份时间短。 2.备份时数据库依然…...
【力扣每日一题】2023.10.8 股票价格波动
目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 这道题是程序设计题,要我们实现一个类,一共是四个功能,第一个是给一个时间戳和价格,表示该…...
Linux隐藏文件或文件夹
在Linux中,以点(.)开头的文件或文件夹是隐藏文件或隐藏文件夹。要创建一个隐藏文件或文件夹,可以使用以下命令: 创建隐藏文件: touch .filename这将在当前目录下创建一个名为 “.filename” 的隐藏文件。…...
leetcode - 365周赛
一,2873.有序三元组中的最大值 I 该题的数据范围小,直接遍历: class Solution {public long maximumTripletValue(int[] nums) {int n nums.length;long ans 0;for(int i0; i<n-2; i){for(int ji1; j<n-1; j){for(int kj1; k<…...
为什么mac上有的软件删除不掉?
对于Mac用户来说,软件卸载通常是一个相对简单的过程。然而,有时你可能会发现某些软件似乎“顽固不化”,即使按照常规方式尝试卸载,也依然存在于你的电脑上。这到底是为什么呢?本文将探讨这一问题的可能原因。 1.卸载失…...
【vue3】wacth监听,监听ref定义的数据,监听reactive定义的数据,详解踩坑点
假期第二篇,对于基础的知识点,我感觉自己还是很薄弱的。 趁着假期,再去复习一遍 之前已经记录了一篇【vue3基础知识点-computed和watch】 今天在学习的过程中发现,之前记录的这一篇果然是很基础的,很多东西都讲的不够…...
跨境电商如何通过软文建立品牌形象?
在全球产业链结构重塑后的今天,越来越多的企业意识到想要可持续发展,就需要在建立品牌形象,在用户心中留下深刻印象,那么应该如何有效建立品牌形象呢?可以利用软文来打造品牌形象,接下来媒介盒子就告诉大家…...
我做了一个简易P图(参数图)分析软件
P图(即参数图,Parameter Diagram),是一个结构化的工具,帮助大家对产品更好地进行分析。 典型P图格式 P图最好是和FMEA软件联动起来,如国可工软的FMEA软件有P图分析这个功能。 单纯的P图分析软件很少,为了方便做P图分…...
209.Flink(四):状态,按键分区,算子状态,状态后端。容错机制,检查点,保存点。状态一致性。flink与kafka整合
一、状态 1.概述 算子任务可以分为有状态、无状态两种。 无状态:filter,map这种,每次都是独立事件有状态:sum这种,每次处理数据需要额外一个状态值来辅助。这个额外的值就叫“状态”2.状态的分类 (1)托管状态(Managed State)和原始状态(Raw State) 托管状态就是由…...
rabbitmq查看节点信息命令失败
不影响访问rabbitmq,但是无法使用 命令查看节点信息 等 查看节点信息命令:rabbitmq-diagnostics status --node rabbitJHComputer Error: unable to perform an operation on node ‘rabbitJHComputer‘. Please see diagnostics informatio rabbitmq-…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...
WEB3全栈开发——面试专业技能点P4数据库
一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库,基于 mysql 库改进而来,具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点: 支持 Promise / async-await…...
门静脉高压——表现
一、门静脉高压表现 00:01 1. 门静脉构成 00:13 组成结构:由肠系膜上静脉和脾静脉汇合构成,是肝脏血液供应的主要来源。淤血后果:门静脉淤血会同时导致脾静脉和肠系膜上静脉淤血,引发后续系列症状。 2. 脾大和脾功能亢进 00:46 …...
HTTPS证书一年多少钱?
HTTPS证书作为保障网站数据传输安全的重要工具,成为众多网站运营者的必备选择。然而,面对市场上种类繁多的HTTPS证书,其一年费用究竟是多少,又受哪些因素影响呢? 首先,HTTPS证书通常在PinTrust这样的专业平…...
LangChain【6】之输出解析器:结构化LLM响应的关键工具
文章目录 一 LangChain输出解析器概述1.1 什么是输出解析器?1.2 主要功能与工作原理1.3 常用解析器类型 二 主要输出解析器类型2.1 Pydantic/Json输出解析器2.2 结构化输出解析器2.3 列表解析器2.4 日期解析器2.5 Json输出解析器2.6 xml输出解析器 三 高级使用技巧3…...
