C++ 设计模式——职责链模式

news2024/9/22 5:28:21

目录

    • C++ 设计模式——职责链模式
      • 1. 主要组成成分
      • 2. 逐步构建职责链模式
        • 步骤1:定义处理者接口
        • 步骤2:定义抽象处理者
        • 步骤3: 创建具体处理者
        • 步骤4: 配置职责链
      • 3. 备忘录模式 UML 图
        • UML 图解析
      • 4. 单纯与非单纯的职责链模式
        • 4.1 敏感词过滤器父类
        • 4.2 具体过滤器实现
        • 4.3 主函数
      • 5. 职责链模式的优点
      • 6. 职责链模式的缺点
      • 7. 职责链模式的适用场景
      • 总结
      • 完整代码

C++ 设计模式——职责链模式

职责链(Chain Of Responsibility)模式也叫责任链模式,是一种行为型模式,用于将一个请求传递给一个链中的若干对象,哪个对象适合处理这个请求就让哪个对象来处理。职责链看起来与传统数据结构中的“链表”非常类似。

引人“职责链”设计模式的定义(实现意图):使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链(构成对象链),并沿着这条链传递该请求,直到有一个对象处理它为止。

1. 主要组成成分

  1. 处理器接口(Handler Interface):定义了一个处理请求的接口,通常包含一个方法用于接收或处理请求。这个接口不确定请求的具体处理者。
  2. 具体处理器(Concrete Handlers):实现处理器接口的类。每个处理器会对请求做出处理或者将请求传递给链中的下一个处理者。具体处理器决定了处理请求的条件和方式。
  3. 请求类(Request):通常是包含多个属性的类,这些属性决定了哪个具体处理器应该处理该请求。
  4. 客户端(Client):负责创建处理链,并向链的第一个处理器发送请求。客户端不关心请求如何以及由谁处理,这样做实现了发送者和接收者之间的解耦。

2. 逐步构建职责链模式

以下示例展示了如何实现一个用于处理加薪请求的职责链模式。此示例包含三个不同级别的审批者:部门经理、技术总监和总经理,各自能够处理特定范围的加薪请求。以下是构建职责链模式的详细步骤:

步骤1:定义处理者接口

已定义 RaiseRequest 类封装了加薪请求,其中包括员工姓名和加薪金额。

//加薪请求类
class RaiseRequest
{
public:
    //构造函数
    RaiseRequest(const string& sname, int salfigure) :m_sname(sname), m_isalfigure(salfigure) {}

    //获取请求加薪的人员名字
    const string& getName() const
    {
        return m_sname;
    }
    //获取请求加薪的数字
    int getSalFigure() const
    {
        return m_isalfigure;
    }

private:
    string m_sname;      //请求加薪的人员名字
    int    m_isalfigure; //请求加薪的数字
};
步骤2:定义抽象处理者

定义了一个名为 ParSalApprover 的抽象基类,其中包含一个处理请求的纯虚函数 processRequest 和一个函数 setNextChain 用于设置链中的下一个处理者。

//薪水审批者父类
class ParSalApprover
{
public:
    ParSalApprover() :m_nextChain(nullptr) {}
    virtual ~ParSalApprover() {} //做父类时析构函数应该为虚函数

    //设置指向的职责链中的下个审批者
    void setNextChain(ParSalApprover* next)
    {
        m_nextChain = next;
    }

    //处理加薪请求
    virtual void processRequest(const RaiseRequest& req) = 0;

protected:
    //找链中的下个对象并把请求投递给下个链中的对象
    void sendRequestToNextHandler(const RaiseRequest& req)
    {
        //找链中的下个对象
        if (m_nextChain != nullptr)
        {
            //把请求投递给链中的下个对象
            m_nextChain->processRequest(req);
        }
        else
        {
            //没找到链中的下个对象,程序流程执行这里似乎不应该
            cout << req.getName() << "的加薪要求为:" << req.getSalFigure() << "元,但无人能够审批!" << endl;
        }
    }

private:
    ParSalApprover* m_nextChain; //指向下一个审批者(对象)的多态指针(指向自身类型),每个都指向下一个,就会构成一个职责链(链表)
};
步骤3: 创建具体处理者

创建了三个具体处理者:depManager_SA, CTO_SA, 和 genManager_SA,每个类根据其规则处理请求。

//部门经理子类
class depManager_SA :public ParSalApprover
{
public:
    //处理加薪请求
    virtual void processRequest(const RaiseRequest& req)
    {
        int salfigure = req.getSalFigure();
        if (salfigure <= 1000)
        {
            //如果自己能处理,则自己处理
            cout << req.getName() << "的加薪要求为:" << salfigure << "元,部门经理审批通过!" << endl;
        }
        else
        {
            //自己不能处理,尝试找链中的下个对象来处理
            sendRequestToNextHandler(req);
        }
    }
};

//技术总监子类
class CTO_SA :public ParSalApprover
{
    //处理加薪请求
    virtual void processRequest(const RaiseRequest& req)
    {
        int salfigure = req.getSalFigure();
        if (salfigure > 1000 && salfigure <= 5000)
        {
            //如果自己能处理,则自己处理
            cout << req.getName() << "的加薪要求为:" << salfigure << "元,技术总监审批通过!" << endl;
        }
        else
        {
            sendRequestToNextHandler(req);//自己不能处理,尝试找链中的下个对象来处理
        }
    }
};

//总经理子类
class genManager_SA :public ParSalApprover
{
public:
    //处理加薪请求
    virtual void processRequest(const RaiseRequest& req)
    {
        int salfigure = req.getSalFigure();
        if (salfigure > 5000)
        {
            //如果自己能处理,则自己处理
            cout << req.getName() << "的加薪要求为:" << salfigure << "元,总经理审批通过!" << endl;
        }
        else
        {
            sendRequestToNextHandler(req);//自己不能处理,尝试找链中的下个对象来处理
        }
    }
};
步骤4: 配置职责链

在主函数中,创建处理者对象,并按逻辑顺序将它们连接起来形成一个链。

int main()
{
    //(1)创建出职责链中包含的各个对象(部门经理、技术总监、总经理)
    ParSalApprover* pzzlinkobj1 = new depManager_SA();
    ParSalApprover* pzzlinkobj2 = new CTO_SA();
    ParSalApprover* pzzlinkobj3 = new genManager_SA();
    //(2)将这些对象串在一起构成职责链(链表),现在职责链中pzzlinkobj1排在最前面,pzzlinkobj3排在最后面
    pzzlinkobj1->setNextChain(pzzlinkobj2);
    pzzlinkobj2->setNextChain(pzzlinkobj3);
    pzzlinkobj3->setNextChain(nullptr); //可以不写此行,因为ParSalApprover构造函数中设置了m_nextChain为nullptr

    //(3)创建几位员工关于加薪的请求(对象)
    RaiseRequest emp1Req("张三", 15000);//张三要求加薪1.5万
    RaiseRequest emp2Req("李四", 3500);//李四要求加薪3千5
    RaiseRequest emp3Req("王二", 800);//王二要求加薪8百
    //看看每位员工的加薪请求由职责链中的哪个对象(部门经理、技术总监、总经理)来处理,从职责链中排在最前面的接收者(pzzlinkobj1)开始
    pzzlinkobj1->processRequest(emp1Req);
    pzzlinkobj1->processRequest(emp2Req);
    pzzlinkobj1->processRequest(emp3Req);

    //(4)释放资源
    delete pzzlinkobj1;
    delete pzzlinkobj2;
    delete pzzlinkobj3;

    return 0;
}

3. 备忘录模式 UML 图

职责链模式 UML 图

UML 图解析

职责链模式的 UML 图中包含3种角色:

  1. Handler (处理者):
    • 作用:定义处理请求的接口(通常为 processRequest),同时也记录了链中下一个处理者的引用(在本例中使用 m_nextChain 来记录)。
    • 实现:在示例中,ParSalApprover 类扮演此角色,提供了设置下一个处理者和处理请求的基本框架。
  2. ConcreteHandler (具体处理者):
    • 作用:实现具体请求的处理逻辑。如果当前处理者无法完全处理请求,则将请求传递给链中的下一个处理者(后继者)。
    • 实现:在示例中,depManager_SACTO_SAgenManager_SA 类是具体处理者。每个类都有条件判断是否能处理请求,不能处理时将请求传递给链上的下一个处理者。
  3. Client (请求者/客户端):
    • 作用:向职责链上的具体处理者对象提交处理请求。客户端负责初始化处理链并触发请求处理过程。
    • 实现:在示例中,主函数 main 执行了客户端的角色。除了提交处理请求,它还负责创建职责链对象并搭建职责链。这部分通常是由客户端完成,因为职责链的结构和顺序可能根据不同的业务场景需要不同的配置。

4. 单纯与非单纯的职责链模式

在设计模式中,职责链模式可以分为两种形式:单纯的职责链模式和非单纯的职责链模式。这两种形式主要区别在于请求在链中的传递方式和处理者的责任范围。非单纯的职责链模式中允许一个请求被某个接收者处理后继续沿着职责链传递,其他处理者仍有机会继续处理该请求,这样的职责链往往也被称为功能链,即便一个请求未被任何处理者对象处理,在非单纯的职责链模式中也是允许的。功能链一般用于权限的多次多重校验、数据的多重检查和过滤等场合。

下面给出这个敏感词过滤器非单纯职责链模式范例(参照前面的范例书写即可)。该过滤器能够把聊天内容中涉及性、脏话、政治内容的关键词寻找出来并用一些其他符号来代替。首先创建敏感词过滤器父类,代码如下:

4.1 敏感词过滤器父类

定义一个抽象基类,其中包含将请求传递给链中下一个处理者的方法。

//敏感词过滤器父类
class ParWordFilter
{
public:
    ParWordFilter() :m_nextChain(nullptr) {}
    virtual ~ParWordFilter() {} //做父类时析构函数应该为虚函数

    //设置指向的职责链中的下个过滤器
    void setNextChain(ParWordFilter* next)
    {
        m_nextChain = next;
    }

    //处理敏感词过滤请求
    virtual string processRequest(string strWord) = 0;

protected:
    //找链中的下个对象并把请求投递给下个链中的对象
    string sendRequestToNextHandler(string strWord)
    {
        //找链中的下个对象
        if (m_nextChain != nullptr)
        {
            //把请求投递给链中的下个对象
            return m_nextChain->processRequest(strWord);
        }
        return strWord;
    }
private:
    ParWordFilter* m_nextChain;
};
4.2 具体过滤器实现

接着,创建敏感词过滤器子类共3个,分别用于过滤性、脏话、政治内容,代码如下:

//性敏感词过滤器子类
class SexyWordFilter :public ParWordFilter
{
public:
    virtual string processRequest(string strWord)
    {
        cout << "通过与词库比对,在strWord中查找\"性\"敏感词并用XXX来替换!" << endl;
        strWord += "XXX"; //测试代码,具体的实现逻辑略......
        return sendRequestToNextHandler(strWord);
    }
};

//脏话词过滤器子类
class DirtyWordFilter :public ParWordFilter
{
public:
    virtual string processRequest(string strWord)
    {
        cout << "通过与词库比对,在strWord中查找\"脏话\"敏感词并用YYY来替换!" << endl;
        strWord += "YYY";
        return sendRequestToNextHandler(strWord);
    }
};

//政治敏感词过滤器子类
class PoliticsWordFilter :public ParWordFilter
{
public:
    virtual string processRequest(string strWord)
    {
        cout << "通过与词库比对,在strWord中查找\"政治\"敏感词并用ZZZ来替换!" << endl;
        strWord += "ZZZ";
        return sendRequestToNextHandler(strWord);
    }
};
4.3 主函数

在主函数中创建和配置职责链。

int main()
{  
    //(1)创建出职责链中包含的各个对象(性敏感词过滤器、脏话词过滤器、政治敏感词过滤器)
    ParWordFilter* pwflinkobj1 = new SexyWordFilter();
    ParWordFilter* pwflinkobj2 = new DirtyWordFilter();
    ParWordFilter* pwflinkobj3 = new PoliticsWordFilter();
    //(2)将这些对象串在一起构成职责链(链表),现在职责链中pwflinkobj1排在最前面,pwflinkobj3排在最后面
    pwflinkobj1->setNextChain(pwflinkobj2);
    pwflinkobj2->setNextChain(pwflinkobj3);
    pwflinkobj3->setNextChain(nullptr);
    string strWordFilterResult = pwflinkobj1->processRequest("你好,这里是过滤敏感词测试范例"); //从职责链中排在最前面的接收者(pwflinkobj1)开始,processRequest的参数代表的是聊天内容
    cout << "对敏感词过滤后的结果为:" << strWordFilterResult << endl;
    //(3)释放资源
    delete pwflinkobj1;
    delete pwflinkobj2;
    delete pwflinkobj3;
    
    return 0;
}

执行结果:

通过与词库比对,在strWord中查找"性"敏感词并用XXX来替换!
通过与词库比对,在strWord中查找"脏话"敏感词并用YYY来替换!
通过与词库比对,在strWord中查找"政治"敏感词并用ZZZ来替换!
对敏感词过滤后的结果为:你好,这里是过滤敏感词测试范例XXXYYYZZZ

从结果可以看到,聊天内容(请求)先经过性敏感词过滤器处理,然后再把处理后的聊天内容(请求)传递给脏话敏感词过滤器,脏话敏感词过滤器处理完后再传递给政治敏感词过滤器,这些过滤器形成了一个链条。链条上的每个过滤器各自承担自己的处理职责,经过多次被处理并被放行传递到下一个过滤器的过程,最终处理结果被返回到strWordFilterResult中。

5. 职责链模式的优点

  • 减少请求的发送者和接收者之间的耦合:发送者和接收者不需要知道彼此的具体细节。
  • 增强了系统的灵活性:可以动态地添加或修改处理链,而不影响其他部分。
  • 增强了给定请求的处理机会:请求可以被多个对象处理,不必绑定到特定的处理者。

6. 职责链模式的缺点

  • 请求可能未被处理:如果链配置不当,请求可能会到达链的末端而未被处理。
  • 性能问题:在某些情况下,由于需要在链上进行多次处理判断,可能会引入性能瓶颈。
  • 调试困难:由于处理过程的动态性,可能难以跟踪请求在链中的传递路径。

7. 职责链模式的适用场景

  1. 多个对象可以处理同一请求:当多个对象都可能对请求进行处理,但具体由哪个对象处理在运行时才确定时,职责链模式提供了一种灵活的处理方式。
  2. 不明确具体接收者:在请求的发送者不需要知道请求的具体接收者是谁的情况下,使用职责链模式可以将发送者和接收者解耦。
  3. 可动态指定处理的顺序:当需要在运行时动态改变请求处理者的顺序或者动态添加新的处理者时,职责链模式能够提供这种灵活性。

总结

职责链模式通过建立一条对象链来处理请求,实现了请求发送者和接收者之间的解耦。它在处理具有不同处理级别的请求时特别有用,如日志记录、异常处理等场景。然而,使用时需要注意避免请求在链中过度传递,以及确保所有请求都能得到适当处理。

完整代码

#include <iostream>
using namespace std;

//加薪请求类
class RaiseRequest
{
public:
    //构造函数
    RaiseRequest(const string& sname, int salfigure) :m_sname(sname), m_isalfigure(salfigure) {}

    //获取请求加薪的人员名字
    const string& getName() const
    {
        return m_sname;
    }
    //获取请求加薪的数字
    int getSalFigure() const
    {
        return m_isalfigure;
    }

private:
    string m_sname;      //请求加薪的人员名字
    int    m_isalfigure; //请求加薪的数字
};

//-------------------
//薪水审批者父类
class ParSalApprover
{
public:
    ParSalApprover() :m_nextChain(nullptr) {}
    virtual ~ParSalApprover() {} //做父类时析构函数应该为虚函数

    //设置指向的职责链中的下个审批者
    void setNextChain(ParSalApprover* next)
    {
        m_nextChain = next;
    }

    //处理加薪请求
    virtual void processRequest(const RaiseRequest& req) = 0;

protected:
    //找链中的下个对象并把请求投递给下个链中的对象
    void sendRequestToNextHandler(const RaiseRequest& req)
    {
        //找链中的下个对象
        if (m_nextChain != nullptr)
        {
            //把请求投递给链中的下个对象
            m_nextChain->processRequest(req);
        }
        else
        {
            //没找到链中的下个对象,程序流程执行这里似乎不应该
            cout << req.getName() << "的加薪要求为:" << req.getSalFigure() << "元,但无人能够审批!" << endl;
        }
    }

private:
    ParSalApprover* m_nextChain; //指向下一个审批者(对象)的多态指针(指向自身类型),每个都指向下一个,就会构成一个职责链(链表)
};

//部门经理子类
class depManager_SA :public ParSalApprover
{
public:
    //处理加薪请求
    virtual void processRequest(const RaiseRequest& req)
    {
        int salfigure = req.getSalFigure();
        if (salfigure <= 1000)
        {
            //如果自己能处理,则自己处理
            cout << req.getName() << "的加薪要求为:" << salfigure << "元,部门经理审批通过!" << endl;
        }
        else
        {
            //自己不能处理,尝试找链中的下个对象来处理
            sendRequestToNextHandler(req);
        }
    }
};

//技术总监子类
class CTO_SA :public ParSalApprover
{
    //处理加薪请求
    virtual void processRequest(const RaiseRequest& req)
    {
        int salfigure = req.getSalFigure();
        if (salfigure > 1000 && salfigure <= 5000)
        {
            //如果自己能处理,则自己处理
            cout << req.getName() << "的加薪要求为:" << salfigure << "元,技术总监审批通过!" << endl;
        }
        else
        {
            sendRequestToNextHandler(req);//自己不能处理,尝试找链中的下个对象来处理
        }
    }
};

//总经理子类
class genManager_SA :public ParSalApprover
{
public:
    //处理加薪请求
    virtual void processRequest(const RaiseRequest& req)
    {
        int salfigure = req.getSalFigure();
        if (salfigure > 5000)
        {
            //如果自己能处理,则自己处理
            cout << req.getName() << "的加薪要求为:" << salfigure << "元,总经理审批通过!" << endl;
        }
        else
        {
            sendRequestToNextHandler(req);//自己不能处理,尝试找链中的下个对象来处理
        }
    }
};

//敏感词过滤器父类
class ParWordFilter
{
public:
    ParWordFilter() :m_nextChain(nullptr) {}
    virtual ~ParWordFilter() {} //做父类时析构函数应该为虚函数

    //设置指向的职责链中的下个过滤器
    void setNextChain(ParWordFilter* next)
    {
        m_nextChain = next;
    }

    //处理敏感词过滤请求
    virtual string processRequest(string strWord) = 0;

protected:
    //找链中的下个对象并把请求投递给下个链中的对象
    string sendRequestToNextHandler(string strWord)
    {
        //找链中的下个对象
        if (m_nextChain != nullptr)
        {
            //把请求投递给链中的下个对象
            return m_nextChain->processRequest(strWord);
        }
        return strWord;
    }
private:
    ParWordFilter* m_nextChain;
};

//性敏感词过滤器子类
class SexyWordFilter :public ParWordFilter
{
public:
    virtual string processRequest(string strWord)
    {
        cout << "通过与词库比对,在strWord中查找\"性\"敏感词并用XXX来替换!" << endl;
        strWord += "XXX"; //测试代码,具体的实现逻辑略......
        return sendRequestToNextHandler(strWord);
    }
};

//脏话词过滤器子类
class DirtyWordFilter :public ParWordFilter
{
public:
    virtual string processRequest(string strWord)
    {
        cout << "通过与词库比对,在strWord中查找\"脏话\"敏感词并用YYY来替换!" << endl;
        strWord += "YYY";
        return sendRequestToNextHandler(strWord);
    }
};

//政治敏感词过滤器子类
class PoliticsWordFilter :public ParWordFilter
{
public:
    virtual string processRequest(string strWord)
    {
        cout << "通过与词库比对,在strWord中查找\"政治\"敏感词并用ZZZ来替换!" << endl;
        strWord += "ZZZ";
        return sendRequestToNextHandler(strWord);
    }
};

int main()
{

    //(1)创建出职责链中包含的各个对象(部门经理、技术总监、总经理)
    ParSalApprover* pzzlinkobj1 = new depManager_SA();
    ParSalApprover* pzzlinkobj2 = new CTO_SA();
    ParSalApprover* pzzlinkobj3 = new genManager_SA();
    //(2)将这些对象串在一起构成职责链(链表),现在职责链中pzzlinkobj1排在最前面,pzzlinkobj3排在最后面
    pzzlinkobj1->setNextChain(pzzlinkobj2);
    pzzlinkobj2->setNextChain(pzzlinkobj3);
    pzzlinkobj3->setNextChain(nullptr); //可以不写此行,因为ParSalApprover构造函数中设置了m_nextChain为nullptr

    //(3)创建几位员工关于加薪的请求(对象)
    RaiseRequest emp1Req("张三", 15000);//张三要求加薪1.5万
    RaiseRequest emp2Req("李四", 3500);//李四要求加薪3千5
    RaiseRequest emp3Req("王二", 800);//王二要求加薪8百
    //看看每位员工的加薪请求由职责链中的哪个对象(部门经理、技术总监、总经理)来处理,从职责链中排在最前面的接收者(pzzlinkobj1)开始
    pzzlinkobj1->processRequest(emp1Req);
    pzzlinkobj1->processRequest(emp2Req);
    pzzlinkobj1->processRequest(emp3Req);

    //(4)释放资源
    delete pzzlinkobj1;
    delete pzzlinkobj2;
    delete pzzlinkobj3;


    //(1)创建出职责链中包含的各个对象(性敏感词过滤器、脏话词过滤器、政治敏感词过滤器)
    ParWordFilter* pwflinkobj1 = new SexyWordFilter();
    ParWordFilter* pwflinkobj2 = new DirtyWordFilter();
    ParWordFilter* pwflinkobj3 = new PoliticsWordFilter();

    //(2)将这些对象串在一起构成职责链(链表),现在职责链中pwflinkobj1排在最前面,pwflinkobj3排在最后面
    pwflinkobj1->setNextChain(pwflinkobj2);
    pwflinkobj2->setNextChain(pwflinkobj3);
    pwflinkobj3->setNextChain(nullptr);
    string strWordFilterResult = pwflinkobj1->processRequest("你好,这里是过滤敏感词测试范例"); //从职责链中排在最前面的接收者(pwflinkobj1)开始,processRequest的参数代表的是聊天内容
    cout << "对敏感词过滤后的结果为:" << strWordFilterResult << endl;

    //(3)释放资源
    delete pwflinkobj1;
    delete pwflinkobj2;
    delete pwflinkobj3;


    return 0;
}

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

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

相关文章

C++:类的定义、实例化

目录 一、类的定义 1.1 类的定义格式 1.2 访问限定符 1.3 类域 二、实例化 2.1 实例化概念 2.2 对象大小 一、类的定义 1.1 类的定义格式 • class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后面分号不能省…

设备上的实时自定义手势识别

这篇论文的标题是《On-device Real-time Custom Hand Gesture Recognition》&#xff0c;主要研究了如何在移动设备上实时识别自定义手势。以下是论文的主要内容概述&#xff1a; 摘要&#xff1a; 论文指出现有的手势识别系统大多限于预定义的手势集&#xff0c;但用户和开发…

鸿蒙(HarmonyOS)常见的三种弹窗方式

最近有一个想法&#xff0c;做一个针对鸿蒙官方API的工具箱项目&#xff0c;介绍常用的控件&#xff0c;以及在项目中如何使用&#xff0c;今天介绍Harmony中如何实现弹窗功能。 警告弹窗 警告弹窗是一个App中非常常用的弹窗&#xff0c;例如&#xff1a; 删除一条记录&…

帕金森患者在运动时有哪些类型的运动推荐?

帕金森病患者在进行运动时&#xff0c;可以考虑以下几种类型的运动&#xff1a; 有氧运动&#xff1a;如散步、慢跑、爬山、骑自行车、健美操、广场舞等&#xff0c;这些运动有助于改善心肺功能&#xff0c;同时也能提升肌肉力量和灵活性。 柔性运动&#xff1a;包括瑜伽、太极…

<Rust>egui学习之小部件(七):如何在窗口中添加颜色选择器colorpicker部件?

前言 本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析&#xff0c;主要讲解egui的源代码、部件属性、如何应用。 环境配置 系统&#xff1a;windows 平台&#xff1a;visual studio code 语言&#xff1a;rust 库&#xff1a;egui、eframe 概述 本文是本专栏的第七篇博…

笔记整理—内核!启动!

常规启动时&#xff0c;各镜像都在SD卡中的各种分区中&#xff0c;内核放在kernel分区&#xff0c;从SD卡到DDR的连接处&#xff08;内核不需要进行重定位&#xff0c;直接从链接处启动&#xff09;。uboot从sd卡分区读使用movi命令。 使用fastboot指令可以查看分区情况&#x…

【赵渝强老师】MongoDB的MMAPv1存储引擎

在MongoDB 3.2版本以前&#xff0c;MongoDB使用MMAPv1作为默认的存储引擎。在MMAPv1的存储引擎中&#xff0c;包含以下的组成部分&#xff1a; Database 每个Database由一个.ns名称空间文件及若干个数据文件组成。数据文件从0开始编号&#xff0c;依次为.0、.1、.2等。数据文件…

小心GitHub账号被盗

最近有小伙伴反馈在 GitHub 上解压了不明文件之后&#xff0c;GitHub 账号被盗了。 事情是这样的&#xff1a; 有小伙伴在 GitHub 某仓库的 issue 中正常和人讨论问题&#xff0c;有个人光速回复了一条消息&#xff0c;给了一个链接&#xff0c;让下载一个名为 fix.rar 的文件…

C++系列-STL容器之list

STL容器之list list容器的基本结构list容器的特点list容器的优点list容器的缺点 list容器的构造函数list容器的常用接口list大小及空否list访问list迭代器相关list增删查改push and popinsert其它 list赋值操作 list容器的基本结构 list容器的内部结构是双向循环链表&#xff…

Java笔试面试题AI答之面向对象(8)

文章目录 43. 解释Java接口隔离原则和单一原则如何理解 &#xff1f;单一职责原则&#xff08;Single Responsibility Principle, SRP&#xff09;接口隔离原则&#xff08;Interface Segregation Principle, ISP&#xff09; 44. Java 有没有 goto? 如果有&#xff0c;一般用…

004.Python爬虫系列_web请求全过程剖析(重点)

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

2024年8月31日历史上的今天大事件早读

1449年8月31日 明朝“土木之变” 1907年8月31日 英、法、俄三国协约形成 1914年8月31日 “骆派”京韵大鼓的创建者骆玉笙诞生 1916年8月31日 蔡锷东渡日本养病 1935年8月31日 美国通过《中立法案》 1937年8月31日 日本华北方面军成立 1941年8月31日 晋察冀边区完成民主大…

2024最新最全:国内外人工智能AI工具网站大全!

国内外人工智能AI工具网站大全&#xff08;一键收藏&#xff0c;应有尽有&#xff09; 摘要一、AI写作工具二、AI图像工具 2.1、常用AI图像工具2.2、AI图片插画生成2.3、AI图片背景移除2.4、AI图片无损调整2.5、AI图片优化修复2.6、AI图片物体抹除 三、AI音频工具四、AI视频工…

南京观海微电子----CMOS门电路(OD门、传输门、双向模拟开关、三态门)

【 1. MOS管】 MOS管&#xff1a;绝缘栅型场效应管。 【 2. CMOS电路】 当NMOS管和PMOS管成对出现在电路中&#xff0c;且二者在工作中互补&#xff0c;称为CMOS管(Complementary Metal-Oxide-Semiconductor)。 电路结构 拉电流 如下图所示&#xff0c;输入低电平&#xff…

王者荣耀 设置游戏头像 不用微信头像

我们在微信 我 选择 设置 在里面找到 个人信息与权限 如果找不到看看有木有一个叫隐私的选项 点击 进入之后 选择授权管理 找到王者荣耀 然后点击右侧的小箭头进入 点击下面的 解除授权 确认一下 解除授权 然后重新打开王者 选择微信登录 我们这里 选择新建昵称头像 选…

线性代数之线性方程组

目录 线性方程组 1. 解的个数 齐次线性方程组&#xff1a; 非齐次线性方程组&#xff1a; 2. 齐次线性方程组的解 3. 非齐次线性方程组的解 4. 使用 Python 和 NumPy 求解线性方程组 示例代码 齐次线性方程组 非齐次线性方程组 示例结果 齐次线性方程组 非齐次线性…

Unity获取SceneView尺寸

获取SceneView尺寸 var sceneView SceneView.lastActiveSceneView; var size new Vector2(sceneView.position.width,sceneView.position.height);

Elasticsearch学习(1)-mac系统安装elasticsearch基础

Elasticsearch基础 1. 传统数据库与elasticsarch2. 下载Elasticsearch7. 经过上述所有操作&#xff0c;就可以得到一个具体的连接可视化页面3. 安装kibana4. 其余知识点 elasticsearch是什么&#xff1f; Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能…

sql-labs靶场(41-50)

四十一 1.查看数据库名 ?id-1 union select 1,2,database()-- 2.查看表名 ?id-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schemadatabase()-- 3.查看user表列名 ?id-1 union select 1,group_concat(column_name),3 from…

SpringMVC处理流程介绍

SpringMVC请求处理流程 发起请求到前端控制器(DispatcherServlet)前端控制器请求HandlerMapping查找Handler(可以根据xml配置,注解进行查找) 对应Spring源码 //在类DispatcherServlet里面 protected void doDispatch(HttpServletRequest request, HttpServletResponse respon…