软件设计原则 1小时系列 (C++版)

news2024/11/27 0:35:00

文章目录

  • 前言
    • 基本概念
  • 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描述。

基本概念

  1. 📌可维护性质

    在不破坏原有代码设计,不要引入新bug的情况下,能够快速修改或者添加代码

    生活案例:比如一个iPhone在维修摄像头的时候,如果一个手抖,就可能呆滞喇叭或者麦克风损坏,从而影响了通讯或者音视频功能,因为它们都集成在一个电路板上。但是,单反在维修的时候,就不存在这种情况‘

  2. 📌可扩展性

    在不修改或者少量修改原有代码的情况下,可以通过扩展的方式添加新的功能代码

    生活案例:中秋到了,拿着iPhone想要拍个月亮发朋友圈,但是不管怎么拍,效果都不好。这个时候,只见隔壁老王把单发装在三脚架上,然后换上长焦镜头,“咔嚓”一声,我凑过去一看,“哇,真的是又大又圆啊!”。这个时候,单反可以根据不同的拍摄场景,扩展不同的镜头。

  3. 📌可复用性

    尽量减少代码的重复编写,直接复用已有的代码

    生活案例:开发教务系统的时候,直接复用权限管理模块

  4. 📌内聚性

    模块内部元素的紧密程度,内聚性越高,那么模块独立性越好,可维护性,复用性也越高

  5. 📌耦合性

    模块与模块之间的关联关系,耦合度越高,那么模块与模块之间的关联越复杂,那么可维护性,复用性越差

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

尽量先适用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现

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

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

  1. 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为”白箱“复用。
  2. 子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展和维护。

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

  1. 它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称”黑箱“复用。
  2. 对象间的耦合度低。可以在类的成员位置声明抽象(抽象类或者接口

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 稳定抽象原则

一个包的抽象程度应该和其他稳定程度一致。

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

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

相关文章

tailscale自建headscale和derp中继

tailscale自建headscale和derp中继 Tailscale 官方的 DERP 中继服务器全部在境外&#xff0c;在国内的网络环境中不一定能稳定连接&#xff0c;所以有必要建立自己的 DERP 服务器的。 准备工作&#xff1a; 需要有自己的云服务器&#xff0c;本示例为阿里云轻量服务器需要有…

Tasmota系统之外设配置

Tasmota系统之外设配置 &#x1f388;相关篇《ESP32/ESP8266在线刷写Sonoff Tasmota固件以及配置简要》&#x1f516;这里以ESP32配置DS18B20温度传感器和dht11温湿度传感器为例。 ✨如果想接特定型号的显示屏幕&#xff0c;需要下载指定的固件&#xff0c;目前官方所提供的固件…

剑指offer——JZ36 二叉搜索树与双向链表 解题思路与具体代码【C++】

一、题目描述与要求 二叉搜索树与双向链表_牛客题霸_牛客网 (nowcoder.com) 题目描述 输入一棵二叉搜索树&#xff0c;将该二叉搜索树转换成一个排序的双向链表。如下图所示 数据范围&#xff1a;输入二叉树的节点数 0≤n≤1000&#xff0c;二叉树中每个节点的值 0≤val≤10…

“首站告捷 完美收官” | 风丘-EVM ASIA 2023精彩锦集

2023年9月19-21日&#xff0c;风丘携手德国IPETRONIK首次亮相马来西亚-EVM ASIA 2023——该地区第一大电动汽车、移动、制造和汽车零部件展览会&#xff0c;为大家呈现了在汽车测试、车辆诊断领域里专业的研发测试工具及创新解决方案&#xff0c;吸引了众多客户驻足洽谈。 无法…

SpringBoot-黑马程序员-学习笔记(一)

8.pom文件中的parent 我们使用普通maven项目导入依赖时&#xff0c;通常需要在导入依赖的时候指定版本号&#xff0c;而springboot项目不需要指定版本号&#xff0c;会根据当前springboot的版本来下载对应的最稳定的依赖版本。 点开pom文件会看到这个&#xff1a; 继承了一个…

WebGoat 靶场 JWT tokens 四 五 七关通关教程

文章目录 webGoat靶场第 四 关 修改投票数第五关第七关 你购买书&#xff0c;让Tom用户付钱 webGoat靶场 越权漏洞 将webgoat-server-8.1.0.jar复制到kali虚拟机中 sudo java -jar webgoat-server-8.1.0.jar --server.port8888解释&#xff1a; java&#xff1a;这是用于执行…

WebKit Inside: CSS 样式表的解析

CSS 全称为层叠样式表(Cascading Style Sheet)&#xff0c;用来定义 HTML 文件最终显示的外观。 为了理解 CSS 的加载与解析&#xff0c;需要对 CSS 样式表的组成&#xff0c;尤其是 CSS Selector 有所了解&#xff0c;相关部分可以参看这里。 HTML 文件里面引入 CSS 样式表有 …

开启AI大模型时代|「Transformer论文精读」

论文地址: https://arxiv.org/pdf/1706.03762v5.pdf 代码地址: https://github.com/tensorflow/tensor2tensor.git 首发&#xff1a;微信公众号「魔方AI空间」&#xff0c;欢迎关注&#xff5e; 大家好&#xff0c;我是魔方君~~ 近年来&#xff0c;人工智能技术发展迅猛&#…

解锁C语言结构体的力量(进阶)

引言&#xff1a;结构体是C语言中的重要部分&#xff0c;也是通向数据结构的一把“钥匙”&#xff0c;之前我们在这篇文章&#xff1a;http://t.csdnimg.cn/fBkBI已经简单的介绍了结构体的基础知识&#xff0c;本篇我们来更进一步的学习结构体。 目录 结构体的内存对齐 结构体…

二维码是啥?

大家好&#xff0c;我是tony4geek。 今天说下二维码。二维码我们每天都在使用。本文将深入探讨二维码的识别原理&#xff0c;了解其背后的技术和算法&#xff0c;以及它是如何将编码的信息解析成可读的文本或链接的。 一、二维码的基本结构 在探讨二维码的识别原理之前&…

这个国庆婚礼是一场接一场的到来,好幸福

爸妈参加了姐姐的游轮婚礼&#xff0c;爸爸诗兴大发作诗一首&#xff0c;虽然没能亲临&#xff0c;但我妈一直有小视频实时转播&#xff0c;新婚的幸福也已经感受到了&#xff01;

自动驾驶学习笔记(二)——Apollo入门

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《2023星火培训【感知专项营】》免费课程—>传送门 文章目录 前言 Ubuntu Linux文件系统 Linux指令…

小程序+Php获取微信手机号

当前通过获取session_key与encryptedData与iv进行解密获取手机号的方法已经不行了,只能通过点击按钮来实现获取微信用户的手机号 1&#xff1a;需要将 button 组件 open-type 的值设置为 getPhoneNumber&#xff0c;当用户点击并同意之后&#xff0c;可以通过 bindgetphonenum…

如何开始学习量子机器学习

一、关于量子计算 这是我关于量子机器学习&#xff08;QML&#xff09;的第二篇文章&#xff0c;这是第一篇&#xff0c;关于为什么你应该开始学习QML。 开始研究量子机器学习很困难&#xff0c;因为我不知道我需要了解多少量子力学和计算知识。我在101年上大学时上了量子力学2…

【计算机网络-自顶向下方法】应用层(SMTP、POP3、DNS)

目录 1. Electronic Mail电子邮件应用画像1.1 电子邮件系统1.2 邮件报文格式1.3 邮件访问 2. DNS&#xff08;Domain Name System&#xff09;2.1 DNS提供的服务2.2 DNS工作机理2.3 DNS资源记录2.4 DNS协议&#xff0c;报文2.5 小结 1. Electronic Mail 电子邮件应用画像 应用…

操作系统备考学习 day7 (2.3.4 ~ 2.3.5)

操作系统备考学习 day7 第二章 进程与线程2.3 同步与互斥2.3.4 信号量 用信号量实现进程互斥、同步、前驱关系信号量机制实现进程互斥信号量机制实现进程同步信号量机制实现前驱关系 2.3.5 经典同步问题生产者-消费者问题多生产者和多消费者模型抽烟者问题读者-写者问题哲学家进…

挑选一款优秀的Web端项目管理软件

Web端的项目管理软件哪个好用&#xff1f;Zoho Projects是一款本土化成熟的国外项目管理软件。选择Zoho Projects最重要的原因除了项目管理工具的基本能力和高级能力它都基本具备、操作上更符合习惯之外&#xff0c;还值得一提的是拥有很多自定义配置的能力&#xff0c;满足我们…

FPGA实现HDMI输入转SDI视频输出,提供4套工程源码和技术支持

目录 1、前言免责声明 2、我目前已有的SDI编解码方案3、设计思路框架核模块解析设计框图IT6802解码芯片配置及采集ADV7611解码芯片配置及采集silicon9011解码芯片配置及采集纯verilog的HDMI 解码模块RGB888转YUV422SPMTE编码SDI模式图像缓存SPMTE SDIGTXGV8500 4、vivado工程1-…

CLIP与DINOv2的图像相似度对比

在计算机视觉领域有两个主要的自监督模型:CLIP和DINOv2。CLIP彻底改变了图像理解并且成为图片和文字之间的桥梁&#xff0c;而DINOv2带来了一种新的自监督学习方法。 在本文中&#xff0c;我们将探讨CLIP和DINOv2的优势和它们直接微妙的差别。我们的目标是发现哪些模型在图像相…

PostgreSQL ash —— pgsentinel插件 学习与踩坑记录

零、 注意事项 测试发现&#xff0c;pgsentinel插件在pg_active_session_history视图记录条数较多时&#xff0c;存在严重的内存占用问题&#xff0c;群里的其他朋友反馈还可能存在严重的内存泄漏问题。本文仅用于学习和测试&#xff0c;未用于生产环境。 设置 pgsentinel_ash.…