设计模式实践:模板方法、观察者与策略模式详解

news2025/4/18 22:55:32

目录

  • 1 模板方法
    • 1.1 模板方法基本概念
    • 1.2 实验
      • 1.2.1 未使用模板方法实现代码
      • 1.2.2 使用模板方法的代码
  • 2 观察者模式
    • 2.1 观察者模式基本概念
    • 2.2 实验
  • 3 策略模式
    • 3.1 策略模式基本概念
    • 3.2 实验

1 模板方法

1.1 模板方法基本概念

  • 定义:一个操作中的算法的骨架 ,而将一些步骤延迟到子类中。 Template Method使得子类可以不
    改变一个算法的结构即可重定义该算法的某些特定步骤。
  • 要点:
    • 最常用的设计模式,子类可以复写父类子流程,使父类的骨架流程丰富
    • 父类 protected 保护子类需要复写的子流程;这样子类的子流程只能父类来调用

1.2 实验

背景
某个品牌动物园,有一套固定的表演流程,但是其中有若干个表演子流程可创新替换,以尝试迭代更新表演流程;

1.2.1 未使用模板方法实现代码

#include <iostream>
using namespace std;

#if 0
class ZooShow {
public:
    void Show0() {
        cout << "show0" << endl;
    }
    void Show2() {
        cout << "show2" << endl;
    }
};

class ZooShowEx {
public:
    void Show1() {
        cout << "show1" << endl;
    }
    void Show3() {
        cout << "show3" << endl;
    }
};

// 不满足单一职责 , 开 扩展 修改闭原则
// 动物园固定流程,迭代创新
// 稳定和变化   一定的方向上变化
#else if 2
class ZooShow {
public:
    ZooShow(int type = 1) : _type(type) {}

public:
    void Show() {
        if (Show0())
            PlayGame(); // 里氏替换
        Show1();
        Show2();
        Show3();
    }

// 接口隔离 不要让用户去选择它们不需要的接口
private:
    void PlayGame() {
        cout << "after Show0, then play game" << endl;
    }

private:
    bool Show0() {
        cout << _type << " show0" << endl;
        return true;
    }

    void Show1() {
        if (_type == 1) {
            cout << _type << " Show1" << endl;
        } else if (_type == 2) {
            cout << _type << " Show1" << endl;
        } else if (_type == 3) {

        }
    }

    void Show2() {
        if (_type == 20) {
            
        }
        cout << "base Show2" << endl;
    }

    void Show3() {
        if (_type == 1) {
            cout << _type << " Show1" << endl;
        } else if (_type == 2) {
            cout << _type << " Show1" << endl;
        }
    }
private:
    int _type;
};

#endif

int main () {
#if 0
    ZooShow *zs = new ZooShow;
    ZooShowEx *zs1 = new ZooShowEx;
    zs->Show0();
    zs1->Show1();
    zs->Show2();
    zs1->Show3();
#else if 2
    ZooShow *zs = new ZooShow(1);
    zs->Show();
#endif
    return 0;
}

分析:

  • 1.缺乏可扩展性
    在当前代码里,ZooShow 类的 Show 方法内包含了很多 if - else 条件判断,用来依据不同的 _type 值执行不同的逻辑。要是需要新增一种表演类型,就得修改 Show 方法,添加新的 if - else 分支。这违背了开闭原则(对扩展开放,对修改关闭),代码的可扩展性较差。例如,如果要增加 _type == 4 的表演流程,就得在各个方法里添加对应的判断逻辑。
  • 2.代码复用性低
    每个表演类型的逻辑都被硬编码在 ZooShow 类的各个方法中,不同表演类型之间的公共逻辑没有得到很好的复用。如果某些表演类型有相似的流程,当前代码无法有效复用这些公共部分,会造成代码冗余。
  • 3.违反单一职责原则
    ZooShow 类承担了过多的职责,它不仅定义了表演的流程,还包含了每种表演类型的具体逻辑**。当表演类型增多或者表演流程发生变化时,这个类会变得越来越复杂,难以维护**。
  • 4.可读性和可维护性差
    大量的 if - else 条件判断使得代码的逻辑变得复杂,降低了代码的可读性。而且,当需要修改或添加新的表演类型时,需要在多个方法中查找和修改相关逻辑,增加了维护的难度。

1.2.2 使用模板方法的代码

学习设计模式 我们可以通过这些 要点

  • 定义:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法。
  • 解决的问题
    确定点:算法骨架
    变化点:子流程需要变化
  • 代码结构
    基类中存骨架流程接口
    所有子流程对子类开放并且是虚函数
    多态使用方式
  • 符合哪些设计原则
    单一职责
    开闭
    依赖倒置:子类扩展时,需要依赖基类的虚函数实现;使用者只依赖接口
    封装变化点:protected
    接口隔离
    最小知道原则
  • 如何扩展
    实现子类继承基类,重写子流程
    通过多态调用方式使用
#include <iostream>
using namespace std;

// 抽象基类,定义表演流程的模板
class ZooShowTemplate {
public:
    // 模板方法,定义表演的整体流程
    void Show() {
        if (Show0())
            PlayGame();
        Show1();
        Show2();
        Show3();
    }

    virtual ~ZooShowTemplate() {}

protected:
    // 具体步骤的虚函数,可在子类中重写
    virtual bool Show0() {
        cout << "show0" << endl;
        return true;
    }

    virtual void PlayGame() {
        cout << "after Show0, then play game" << endl;
    }

    virtual void Show1() = 0;
    virtual void Show2() = 0;
    virtual void Show3() = 0;
};

// 具体表演类型 1
class ZooShowType1 : public ZooShowTemplate {
protected:
    void Show1() override {
        cout << "1 Show1" << endl;
    }

    void Show2() override {
        cout << "base Show2" << endl;
    }

    void Show3() override {
        cout << "1 Show3" << endl;
    }
};

// 具体表演类型 2
class ZooShowType2 : public ZooShowTemplate {
protected:
    void Show1() override {
        cout << "2 Show1" << endl;
    }

    void Show2() override {
        cout << "base Show2" << endl;
    }

    void Show3() override {
        cout << "2 Show3" << endl;
    }
};

int main() {
    ZooShowTemplate* zs1 = new ZooShowType1();
    zs1->Show();

    ZooShowTemplate* zs2 = new ZooShowType2();
    zs2->Show();

    delete zs1;
    delete zs2;

    return 0;
}

解决的问题

  • 确定点(算法骨架):代码里 ZooShowTemplate 类的 Show 方法确定了表演流程这个算法骨架,固定了表演的整体执行顺序。
  • 变化点(子流程需要变化):不同类型的表演,如 ZooShowType1 和 ZooShowType2,它们的 Show1、Show2、Show3 具体实现是不同的,这就是子流程的变化点,通过继承基类并重写相应虚函数来实现不同的子流程

代码结构

  • 基类中存骨架流程接口:ZooShowTemplate 类中定义的 Show 方法就是骨架流程接口,它包含了整个表演流程的逻辑。
  • 所有子流程对子类开放并且是虚函数:Show0、PlayGame、Show1、Show2、Show3 这些子流程方法在 ZooShowTemplate 类中都被定义为虚函数,方便子类重写,实现不同的子流程逻辑。
  • 多态使用方式:在 main 函数中,通过基类指针 ZooShowTemplate* 分别指向 ZooShowType1 和 ZooShowType2 的对象,然后调用 Show 方法,运行时根据实际指向的子类对象调用相应子类重写的方法,体现了多态性。

符合的设计原则

  • 单一职责:ZooShowTemplate 类负责定义表演流程骨架,各个子类负责具体表演类型的子流程实现,职责划分清晰 ,每个类只专注于自己的职责。
  • 开闭:当需要新增一种表演类型时,如 ZooShowType3,只需创建一个新类继承 ZooShowTemplate 并重写相关虚函数,不需要修改 ZooShowTemplate 类的代码,对扩展开放,对修改关闭。
  • 依赖倒置:子类扩展时依赖基类的虚函数实现,比如 ZooShowType1 和 ZooShowType2 依赖 ZooShowTemplate 中定义的虚函数;使用者(main 函数)只依赖 ZooShowTemplate 这个抽象基类接口,而不是具体子类,降低了耦合度。
  • 封装变化点:在 ZooShowTemplate 类中,将一些可能变化的子流程方法(如 Show1、Show2 等)定义为虚函数,并且访问修饰符为 protected,对外部隐藏了具体实现细节,同时方便子类重写来实现变化。
  • 接口隔离:虽然代码中未明显体现接口隔离的典型场景,但从某种程度上,每个子类只实现自己需要的虚函数,没有被迫依赖不需要的接口方法。
  • 最小知道原则:子类只需要了解与自己相关的基类虚函数,不需要了解基类中其他不必要的实现细节,减少了类之间的信息交互。

如何扩展

  • 实现子类继承基类,重写子流程:如代码中 ZooShowType1 和 ZooShowType2 继承自 ZooShowTemplate,并重写了 Show1、Show2、Show3 等子流程方法,实现不同表演类型的定制。
  • 通过多态调用方式使用:在 main 函数中,通过基类指针调用 Show 方法,利用多态性根据实际子类对象调用相应的重写方法,实现不同表演类型的流程执行。

2 观察者模式

2.1 观察者模式基本概念

  • 定义:对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新
  • 特性
    • 松耦合:主题和观察者相互独立,主题无需知道观察者具体细节,只知其实现了观察者接口 。比如电商系统中商品信息(主题)变化,不同的展示模块(观察者)可独立更新,互不干扰。
    • 动态性:观察者可随时添加或移除,不影响系统其他部分 。例如新闻推送系统,新用户(观察者)可随时订阅(添加)或退订(移除)频道(主题)。

2.2 实验

背景:
气象站发布气象资料给数据中心,数据中心经过处理,将气象信息更新到两个不同的显示终端(A和B)
实现伪代码

#include <vector>

//
class IDisplay {
public:
    virtual void Show(float temperature) = 0;
    virtual ~IDisplay() {}
};

class DisplayA : public IDisplay {
public:
    virtual void Show(float temperature);
private:
    void jianyi();
};

class DisplayB : public IDisplay{
public:
    virtual void Show(float temperature);
};

class DisplayC : public IDisplay{
public:
    virtual void Show(float temperature);
};

class WeatherData {
};

class DataCenter {
public:
    void Attach(IDisplay * ob);
    void Detach(IDisplay * ob);
    void Notify() {
        float temper = CalcTemperature();
        for (auto iter = obs.begin(); iter != obs.end(); iter++) {
            (*iter)->Show(temper);
        }
    }

// 接口隔离
private:
    virtual WeatherData * GetWeatherData();

    virtual float CalcTemperature() {
        WeatherData * data = GetWeatherData();
        // ...
        float temper/* = */;
        return temper;
    }
    std::vector<IDisplay*> obs;
};

int main() {
    DataCenter *center = new DataCenter;
    IDisplay *da = new DisplayA();
    IDisplay *db = new DisplayB();
    IDisplay *dc = new DisplayC();
    center->Attach(da);
    center->Attach(db);
    center->Attach(dc);


    
    center->Notify();
    
    //-----
    center->Detach(db);
    center->Notify();
    return 0;
}

定义与解决的问题

  • 定义体现:观察者模式定义对象间一对多依赖关系,代码中 DataCenter 类相当于主题(被观察者),IDisplay 及其派生类**(DisplayA、DisplayB、DisplayC )相当于观察者** 。DataCenter 维护着多个 IDisplay 指针(观察者),当温度数据计算出来(主题状态变化)时,通知所有注册的观察者,符合一对多依赖关系的定义。
  • 稳定点与变化点
    • 稳定点:“一” 对应的是 DataCenter 类,它是主题,在系统中相对稳定,负责管理观察者和通知逻辑。
    • 变化点:“多” 对应的是 IDisplay 的不同派生类实例,如 DisplayA、DisplayB、DisplayC ,可以随时增加新的显示类(“多” 增加 ),或者移除已有的显示类(“多” 减少 ),比如在 main 函数中通过 Attach 和 Detach 方法进行添加和移除操作。

代码结构
-代码定义了主题类 DataCenter ,通过 std::vector<IDisplay*> 来存储观察者。观察者通过抽象接口 IDisplay 定义,具体观察者类 DisplayA、DisplayB、DisplayC 实现该接口。DataCenter 有 Attach、Detach 方法管理观察者,Notify 方法用于通知观察者。结构上满足观察者模式中主题与观察者的基本组织形式。
符合的设计原则

  • 面向接口编程:代码中定义了抽象接口 IDisplay ,DataCenter 类依赖 IDisplay 接口来管理观察者,而不是具体的观察者类(如 DisplayA、DisplayB 等 )。例如 DataCenter 的 Attach 方法接收 IDisplay * 类型参数,体现了面向接口编程,降低了耦合度。
  • 接口隔离:IDisplay 接口只定义了 Show 方法,每个具体的显示类只需要实现这个与自身显示功能相关的方法,没有被迫实现不必要的接口方法。并且 DataCenter 类内部也有一些方法(如 GetWeatherData 等 )相对隔离,符合接口隔离原则。
  • 封装变化点
    attach:在代码中对应 Attach 方法,用于将观察者(IDisplay 的派生类实例 )添加到 DataCenter 的观察者列表中,封装了增加观察者这个变化点。
    detach:对应 Detach 方法,用于从观察者列表中移除观察者,封装了减少观察者这个变化点。

如何扩展

若要扩展系统,比如增加新的显示方式(新的观察者 ),可以创建一个新的类继承自 IDisplay ,实现 Show 方法,然后在 main 函数中通过 DataCenter 的 Attach 方法将其添加到观察者列表中,就能参与到温度数据的显示通知流程中。

3 策略模式

3.1 策略模式基本概念

定义与核心思想

  • 定义一系列算法:把相关算法进行归纳整理,形成一个算法集合。比如电商系统中计算商品折扣,有固定折扣、满减折扣、会员专属折扣等不同算法 。
  • 封装每个算法:将每个算法独立封装在对应的策略类中。以支付场景为例,支付宝支付、微信支付、银行卡支付等,每种支付方式的实现细节都封装在各自的策略类里,外部无需了解具体支付流程(如网络请求、加密处理等 )。
  • 算法可相互替换:在运行时,可根据实际情况灵活切换不同策略,而不影响使用算法的客户端。例如地图导航,用户可在 “最短距离”“最快速度”“避开拥堵” 等不同路径规划策略间切换 。
    组成部分
  • 策略接口(抽象策略角色):定义算法的公共接口,规定算法应具备的方法签名。比如定义一个计算税费的策略接口,其中包含计算税费的抽象方法 calculateTax() 。
  • 具体策略类:实现策略接口,提供具体算法的实现。如上述计算税费的场景,有针对不同地区税率计算税费的具体策略类,像 “北京地区税费计算类”“上海地区税费计算类” 等,分别实现 calculateTax() 方法。
  • 上下文类:持有策略接口的引用,负责在合适时机调用策略对象的算法。例如电商系统中结算模块作为上下文类,它持有税费计算策略接口的引用,在结算时调用具体策略类(如根据收货地区选择对应地区的税费计算策略 )来计算税费。

3.2 实验

背景:某商场节假日有固定促销活动,为了加大促销力度,现提升国庆节促销活动规格
实现

class Context {

};

class ProStategy {
public:
    virtual double CalcPro(const Context &ctx) = 0;
    virtual ~ProStategy(); 
};
// cpp
class VAC_Spring : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_QiXi : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};
class VAC_QiXi1  : public VAC_QiXi {
public:
    virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_Wuyi : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_GuoQing : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};

class VAC_Shengdan : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};

class Promotion {
public:
    Promotion(ProStategy *sss) : s(sss){}
    ~Promotion(){}
    double CalcPromotion(const Context &ctx){
        return s->CalcPro(ctx);
    }
private:
    ProStategy *s;
};

int main () {
    Context ctx;
    ProStategy *s = new VAC_QiXi1();
    Promotion *p = new Promotion(s);
    p->CalcPromotion(ctx);
    return 0;
}

解决的问题

  • 稳定点:在该商场促销场景中,“客户端与算法的调用关系” 是稳定点。从代码看,Promotion 类(客户端)通过构造函数接收 ProStategy 指针(算法相关),并在 CalcPromotion 方法中固定地调用 s->CalcPro(ctx) 来执行促销算法,这种调用关系相对稳定。
  • 变化点
    • 新加算法:当商场要增加新的促销活动时,比如后续可能新增某个节日的促销策略,就需要添加新的具体策略类。像代码中如果要新增 “元旦促销策略”,可以创建新类继承自 ProStategy 并实现 CalcPro 方法。
    • 算法内容改变:已有的促销策略(如 VAC_QiXi 等类 ),其内部的促销计算逻辑(CalcPro 方法的实现 )可能会根据商场需求进行调整和改变。
      代码结构
      定义了抽象策略类 ProStategy ,其中声明了纯虚函数 CalcPro ,用于定义促销算法的接口。一系列具体策略类(VAC_Spring、VAC_QiXi 等 )继承自 ProStategy ,并实现 CalcPro 方法,各自代表不同节日的促销算法。Context 类目前为空,但在策略模式中通常用于存储上下文相关信息,供策略类使用。
      Promotion 类作为上下文类,持有 ProStategy 指针,通过构造函数进行依赖注入(接收具体的策略对象 ),并在 CalcPromotion 方法中调用策略对象的 CalcPro 方法来执行促销计算。

设计原则

  • 接口隔离
    • 依赖注入:Promotion 类通过构造函数 Promotion(ProStategy *sss) 将具体的促销策略对象注入进来,实现了类与具体策略的解耦。比如在 main 函数中可以灵活地将不同的 ProStategy 子类对象(VAC_QiXi1 等 )注入到 Promotion 中。
    • 解决通过一个接口解决两个类的依赖:ProStategy 接口将 Promotion 类和具体的促销策略类(如 VAC_QiXi 等 )解耦,使得 Promotion 类只依赖于抽象接口,而不依赖具体策略类的实现细节,解决了它们之间的依赖问题。
  • 面向接口编程:整个代码围绕 ProStategy 接口展开,Promotion 类依赖 ProStategy 接口,而不是具体的策略类。在 main 函数中也是通过 ProStategy 指针来操作具体的策略对象,体现了面向接口编程,降低了代码间的耦合度。
  • 开闭原则:当需要新增促销策略(如新增节日促销 )时,只需创建新的类继承 ProStategy 并实现 CalcPro 方法,无需修改现有的 Promotion 类以及其他已有的策略类代码,对扩展开放,对修改关闭。
    其实还有一个组合优于继承的原则

如何扩展代码
若要扩展代码,比如增加新的促销策略,只需创建一个新的类继承自 ProStategy ,并实现 CalcPro 方法。然后在 main 函数中,创建该新策略类的对象,并将其注入到 Promotion 类中,即可使用新的促销策略。例如新增 “中秋促销策略”,可以编写一个新类继承 ProStategy ,实现 CalcPro 方法来定义中秋促销的计算逻辑,然后在 main 函数中按现有方式使用这个新策略。
怎么调用

 ProStategy *s = new VAC_QiXi1();
  Promotion *p = new Promotion(s);
  p->CalcPromotion(ctx);

多态调用

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

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

相关文章

Edge 浏览器推出 Copilot Vision:免费实时解析屏幕内容;Aqua Voice:极速 AI 语音输入工具丨日报

开发者朋友们大家好 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real-Time Engagement&#xff09; 领域内「有话题的 技术 」、「有亮点的 产品 」、「有思考的 文章 」、「有态度的 观点 」、「有看…

async-profiler火焰图找出耗CPU方法

事情起于开发应用对依赖的三方包&#xff08;apache等等&#xff09;进行了升级后&#xff08;主要是升级spring&#xff09;&#xff0c;CPU的使用率较原来大幅提升&#xff0c;几个应用提升50%-100%。 查找半天&#xff0c;对比每次版本的cpu火焰图&#xff0c;看不出有什么…

@Autowird 注解与存在多个相同类型对象的解方案

现有一个 Student 类&#xff0c;里面有两个属性&#xff0c;分别为 name 和 id&#xff1b;有一个 StuService 类&#xff0c;里面有两个方法&#xff0c;返回值均为类型为 Student 的对象&#xff1b;还有一个 StuController 类&#xff0c;里面有一个 Student 类型的属性&am…

WordPiece 详解与示例

WordPiece详解 1. 定义与背景 WordPiece 是一种子词分词算法,由谷歌于2012年提出,最初用于语音搜索系统,后广泛应用于机器翻译和BERT等预训练模型。其核心思想是将单词拆分为更小的子词单元(如词根、前缀/后缀),从而解决传统分词方法面临的词汇表过大和未知词(OOV)处…

PVE+CEPH+HA部署搭建测试

一、基本概念介绍 Proxmox VE ‌Proxmox Virtual Environment (Proxmox VE)‌ 是一款开源的虚拟化管理平台&#xff0c;基于 Debian Linux 开发&#xff0c;支持虚拟机和容器的混合部署。它提供基于 Web 的集中管理界面&#xff0c;简化了计算、存储和网络资源的配置与监控。P…

ROS ROS2 机器人深度相机激光雷达多传感器标定工具箱

系列文章目录 目录 系列文章目录 前言 三、标定目标 3.1 使用自定义标定目标 四、数据处理 4.1 相机数据中的标定目标检测 4.2 激光雷达数据中的标定目标检测 输入过滤器&#xff1a; 正常估算&#xff1a; 区域增长&#xff1a; 尺寸过滤器&#xff1a; RANSAC&a…

android rtsp 拉流h264 h265,解码nv12转码nv21耗时卡顿问题及ffmpeg优化

一、 背景介绍及问题概述 项目需求需要在rk3568开发板上面&#xff0c;通过rtsp协议拉流的形式获取摄像头预览&#xff0c;然后进行人脸识别 姿态识别等后续其它操作。由于rtsp协议一般使用h.264 h265视频编码格式&#xff08;也叫 AVC 和 HEVC&#xff09;是不能直接用于后续处…

熊海cms代码审计

目录 sql注入 1. admin/files/login.php 2. admin/files/columnlist.php 3. admin/files/editcolumn.php 4. admin/files/editlink.php 5. admin/files/editsoft.php 6. admin/files/editwz.php 7. admin/files/linklist.php 8. files/software.php 9. files…

DeepSeek 与开源:肥沃土壤孕育 AI 硕果

当 DeepSeek 以低成本推理、多模态能力惊艳全球时&#xff0c;人们惊叹于国产AI技术的「爆发力」&#xff0c;却鲜少有人追问&#xff1a;这份爆发力的根基何在&#xff1f; 答案&#xff0c;藏在中国开源生态二十余年的积淀中。 从倪光南院士呼吁「以开源打破垄断」&#xf…

Maven中clean、compil等操作介绍和Pom.xml中各个标签介绍

文章目录 前言Maven常用命令1.clean2.vaildate3.compile4.test5.package6.verify7.install8.site9.deploy pom.xml标签详解格式<?xml version"1.0" encoding"UTF-8"?>(xml版本和编码)modelVersion&#xff08;xml版本&#xff09;groupId&#xff…

力扣刷题-热题100题-第35题(c++、python)

146. LRU 缓存 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/lru-cache/?envTypestudy-plan-v2&envIdtop-100-liked 双向链表哈希表 内置函数 对于c有list可以充当双向链表&#xff0c;unordered_map充当哈希表&#xff1b;python有OrderedDic…

Nautilus 正式发布:为 Sui 带来可验证的链下隐私计算

作为 Sui 安全工具包中的强大新成员&#xff0c;Nautilus 现已上线 Sui 测试网。它专为 Web3 开发者打造&#xff0c;支持保密且可验证的链下计算。Nautilus 应用运行于开发者自主管理的可信执行环境&#xff08;Trusted Execution Environment&#xff0c;TEE&#xff09;中&a…

云服务器CVM标准型S5实例性能测评——2025腾讯云

腾讯云服务器CVM标准型S5实例具有稳定的计算性能&#xff0c;CPU采用采用 Intel Xeon Cascade Lake 或者 Intel Xeon Cooper Lake 处理器&#xff0c;主频2.5GHz&#xff0c;睿频3.1GHz&#xff0c;CPU内存配置2核2G、2核4G、4核8G、8核16G等配置&#xff0c;公网带宽可选1M、3…

leetcode面试经典算法题——2

链接&#xff1a;https://leetcode.cn/studyplan/top-interview-150/ 20. 有效的括号 给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#x…

Ubuntu20.04安装企业微信

建议先去企业微信官网看一下有没有linux版本&#xff0c;没有的话在按如下方式安装&#xff0c;不过现在是没有的。 方案 1、使用docker容器 2、使用deepin-wine 3、使用星火应用商店 4. 使用星火包deepin-wine 5、使用ukylin-wine 本人对docker不太熟悉&#xff0c;现…

在Ubuntu服务器上部署xinference

一、拉取镜像 docker pull xprobe/xinference:latest二、启动容器&#xff08;GPU&#xff09; docker run -d --name xinference -e XINFERENCE_MODEL_SRCmodelscope -p 9997:9997 --gpus all xprobe/xinference:latest xinference-local -H 0.0.0.0 # 启动一个新的Docker容…

异步编程——微信小程序

1. 前言 引用来自&#xff1a;微信小程序开发中的多线程处理与异步编程_微信小程序 多线程-CSDN博客 微信小程序是基于JavaScript开发的&#xff0c;与浏览器JavaScript不同&#xff0c;小程序运行在WebView内部&#xff0c;没有多线程的概念。小程序的 JavaScript 是单线程的…

STM32 四足机器人常见问题汇总

文章不介绍具体参数&#xff0c;有需求可去网上搜索。 特别声明&#xff1a;不论年龄&#xff0c;不看学历。既然你对这个领域的东西感兴趣&#xff0c;就应该不断培养自己提出问题、思考问题、探索答案的能力。 提出问题&#xff1a;提出问题时&#xff0c;应说明是哪款产品&a…

Windows 下实现 PHP 多版本动态切换管理(适配 phpStudy)+ 一键切换工具源码分享

&#x1f680; Windows 下实现 PHP 多版本动态切换管理&#xff08;适配 phpStudy&#xff09; 一键切换工具源码分享 &#x1f4e6; 工具特点&#x1f9ea; 效果展示&#x1f9f1; 环境要求&#x1f9d1;‍&#x1f4bb; 源码展示&#xff1a;php_switcher.py&#x1f6e0; 打…

ReportLab 导出 PDF(图文表格)

ReportLab 导出 PDF&#xff08;文档创建&#xff09; ReportLab 导出 PDF&#xff08;页面布局&#xff09; ReportLab 导出 PDF&#xff08;图文表格) 文章目录 1. Paragraph&#xff08;段落&#xff09;2. Table&#xff08;表格&#xff09;3. VerticalBarChart&#xff0…