C++ 设计模式——访问者模式

news2024/9/24 7:26:04

目录

    • C++ 设计模式——访问者模式
      • 1. 主要组成成分
      • 2. 逐步构建访问者模式
        • 步骤1: 创建元素接口和具体元素
        • 步骤2: 创建抽象访问者和具体访问者
        • 步骤3:创建对象结构
        • 步骤4: 客户端使用访问者模式
      • 3. 访问者模式 UML 图
        • UML 图解析
      • 4. 访问者模式的优点
      • 5. 访问者模式的缺点
      • 6. 访问者模式适用场景
      • 总结
      • 完整代码

C++ 设计模式——访问者模式

访问者模式(Visitor Pattern)是一种行为设计模式,其目的是将数据结构与数据操作分离,使得在不修改已有程序代码的情况下,可以添加新的操作。这种模式通过定义一个访问者类,来改变一个元素类的执行算法。访问者模式使得你能够在不改变元素类的前提下,定义作用于这些元素的新操作。

引人“访问者”模式的定义(实现意图):提供一个作用于某对象结构中的各元素的操作表示,便可以在不改变各元素类的前提下定义(扩展)作用于这些元素的新操作。

1. 主要组成成分

  1. 抽象访问者(Visitor): 提供一个访问元素的接口,声明了一系列访问具体元素的方法。
  2. 具体访问者(Concrete Visitor): 实现抽象访问者中声明的操作,定义对每个元素的具体处理逻辑。
  3. 元素接口(Element): 声明一个接受访问者的方法(accept)。
  4. 具体元素(Concrete Element): 实现元素接口,通过接受访问者的方式允许访问者对其进行操作。
  5. 对象结构(Object Structure): 能枚举它的元素,可以提供一个高层的接口以允许访问者访问其元素。

2. 逐步构建访问者模式

该示例代码将展示如何实现一个药品管理系统,使用访问者模式来处理不同的操作,如收费、取药和营养建议。

步骤1: 创建元素接口和具体元素

首先,定义一个Medicine类作为所有药品的基类,它包含一个名为accept的方法,该方法用于接受一个访问者对象。然后,创建具体的药品类,如M_asplcrp(阿司匹林肠溶片),M_fftdnhsp(氟伐他汀钠缓释片)和M_dlx(黛力新),它们都继承自Medicine并实现accept方法。

class Visitor; //类前向声明
//药品父类
class Medicine
{
public:
    virtual void Accept(Visitor* pvisitor) = 0;//这里的形参是访问者父类指针
public:
    virtual string getMdcName() = 0;  //药品名称
    virtual float getPrice() = 0;     //药品总价格,单位:元
};


//药品:阿司匹林肠溶片
class M_asplcrp : public Medicine
{
public:
    virtual string getMdcName()
    {
        return "阿司匹林肠溶片";
    }
    virtual float getPrice()
    {
        return 46.8f;    //为简化代码,直接给出药品总价而不单独强调药品数量了,比如该药品医生给开了两盒,一盒是23.4,那么这里直接返回两盒的价格
    }

public:
    virtual void Accept(Visitor* pvisitor);

};
//药品:氟伐他汀钠缓释片
class M_fftdnhsp : public Medicine
{
public:
    virtual string getMdcName()
    {
        return "氟伐他汀钠缓释片";
    }
    virtual float getPrice()
    {
        return 111.3f;    //三盒的价格
    }

public:
    virtual void Accept(Visitor* pvisitor);

};
//药品:黛力新
class M_dlx : public Medicine
{
public:
    virtual string getMdcName()
    {
        return "黛力新";
    }
    virtual float getPrice()
    {
        return 122.0f;    //两盒的价格
    }

public:
    virtual void Accept(Visitor* pvisitor);

};

//各个药品子类Accept方法的实现体代码
void M_asplcrp::Accept(Visitor* pvisitor)
{
    pvisitor->Visit_elm_asplcrp(this);
}
void M_fftdnhsp::Accept(Visitor* pvisitor)
{
    pvisitor->Visit_elm_fftdnhsp(this);
}
void M_dlx::Accept(Visitor* pvisitor)
{
    pvisitor->Visit_elm_dlx(this);
}
步骤2: 创建抽象访问者和具体访问者

然后,定义Visitor类作为抽象访问者,它包含对每种类型药品的访问方法。接着实现具体访问者类如Visitor_SFRY(收费人员),Visitor_QYRY(取药人员)和Visitor_YYS(营养师),分别定义它们如何处理每种药品。

//访问者父类
class Visitor
{
public:
    virtual ~Visitor() {} //做父类时析构函数应该为虚函数

    virtual void Visit_elm_asplcrp(M_asplcrp* pelem) = 0;//访问元素:阿司匹林肠溶片
    virtual void Visit_elm_fftdnhsp(M_fftdnhsp* pelem) = 0;//访问元素:氟伐他汀钠缓释片
    virtual void Visit_elm_dlx(M_dlx* pelem) = 0; //访问元素:黛力新
};

//收费人员访问者子类
class Visitor_SFRY : public Visitor
{
public:
    virtual void Visit_elm_asplcrp(M_asplcrp* pelem)
    {
        float tmpprice = pelem->getPrice();
        cout << "收费人员累计药品“" << pelem->getMdcName() << "”的价格:" << tmpprice << endl;
        m_totalcost += tmpprice;
    }
    virtual void Visit_elm_fftdnhsp(M_fftdnhsp* pelem)
    {
        float tmpprice = pelem->getPrice();
        cout << "收费人员累计药品“" << pelem->getMdcName() << "”的价格:" << tmpprice << endl;
        m_totalcost += tmpprice;
    }
    virtual void Visit_elm_dlx(M_dlx* pelem)
    {
        float tmpprice = pelem->getPrice();
        cout << "收费人员累计药品“" << pelem->getMdcName() << "”的价格:" << tmpprice << endl;
        m_totalcost += tmpprice;
    }

    //返回总费用
    float getTotalCost()
    {
        return m_totalcost;
    }
private:
    float m_totalcost = 0.0f;  //总费用
};

//取药人员访问者子类
class Visitor_QYRY : public Visitor
{
public:
    virtual void Visit_elm_asplcrp(M_asplcrp* pelem)
    {
        cout << "取药人员将药品“" << pelem->getMdcName() << "”拿给了我!" << endl;
    }
    virtual void Visit_elm_fftdnhsp(M_fftdnhsp* pelem)
    {
        cout << "取药人员将药品“" << pelem->getMdcName() << "”拿给了我!" << endl;
    }
    virtual void Visit_elm_dlx(M_dlx* pelem)
    {
        cout << "取药人员将药品“" << pelem->getMdcName() << "”拿给了我!" << endl;
    }
};

//营养师访问者子类
class Visitor_YYS : public Visitor
{
public:
    virtual void Visit_elm_asplcrp(M_asplcrp* pelem)
    {
        cout << "营养师建议:“多吃粗粮少吃油,可以有效的预防血栓”!" << endl;
    }
    virtual void Visit_elm_fftdnhsp(M_fftdnhsp* pelem)
    {
        cout << "营养师建议:“多吃蘑菇、洋葱、,猕猴桃,可以有效的降低血脂”!" << endl;
    }
    virtual void Visit_elm_dlx(M_dlx* pelem)
    {
        cout << "营养师建议:“多出去走走呼吸新鲜空气,多晒太阳,多去人多热闹的地方,保持乐观开朗的心情”!" << endl;
    }
};
步骤3:创建对象结构

接着,定义一个ObjectStructure类来管理药品集合,并允许将访问者应用于这些集合。这个类负责维护药品列表,并提供一个方法来执行访问者的操作。对象结构是连接元素和访问者的桥梁,使得不同的访问者可以对元素集合执行不同的操作。

//对象结构
class ObjectStructure
{
public:
    //增加药品到药品列表中
    void addMedicine(Medicine* p_mdc)
    {
        m_mdclist.push_back(p_mdc);
    }

    void procAction(Visitor* pvisitor)
    {
        for (auto iter = m_mdclist.begin(); iter != m_mdclist.end(); ++iter)
        {
            (*iter)->Accept(pvisitor);
        }
    }
private:
    list <Medicine*> m_mdclist;  //药品列表
};
步骤4: 客户端使用访问者模式

在客户端代码中,创建ObjectStructure对象,添加药品元素,并创建访问者对象。通过调用ObjectStructure的方法,将访问者应用到所有药品上,以实现具体的功能,如收费、取药或提供营养建议。

int main()
{
    Visitor_SFRY visitor_sf; //收费人员访问者子类,里面承载着向我(患者)收费的算法
    M_asplcrp mdc_asplcrp;
    M_fftdnhsp mdc_fftdnhsp;
    M_dlx mdc_dlx;

    //各个元素子类调用Accept接受访问者的访问,就可以实现访问者要实现的功能
    mdc_asplcrp.Accept(&visitor_sf); //累加“阿司匹林肠溶片”的价格
    mdc_fftdnhsp.Accept(&visitor_sf);//累加“氟伐他汀钠缓释片”的价格
    mdc_dlx.Accept(&visitor_sf);     //累加“黛力新”的价格

    cout << "所有药品的总为:" << visitor_sf.getTotalCost() << ",收费人员收取了我的费用!" << endl;

    //----
    Visitor_QYRY visitor_qy; //取药人员访问者子类,里面承载着向我发放药品的算法
    mdc_asplcrp.Accept(&visitor_qy); //我取得“阿司匹林肠溶片”
    mdc_fftdnhsp.Accept(&visitor_qy);// 我取得“氟伐他汀钠缓释片”
    mdc_dlx.Accept(&visitor_qy);     //我取得“黛力新”

    //-----
    Visitor_YYS visitor_yys;  //营养师访问者子类,里面承载着为我配置营养餐的算法
    mdc_asplcrp.Accept(&visitor_yys); //营养师针对治疗预防血栓药“阿司匹林肠溶片”给出的对应的营养餐建议
    mdc_fftdnhsp.Accept(&visitor_yys);//营养师针对降血脂药“氟伐他汀钠缓释片”给出的对应的营养餐建议
    mdc_dlx.Accept(&visitor_yys);     //营养师针对治疗神经紊乱药“黛力新”给出的对应的营养餐建议

    //---------
    ObjectStructure objstruc;
    objstruc.addMedicine(&mdc_asplcrp);
    objstruc.addMedicine(&mdc_fftdnhsp);
    objstruc.addMedicine(&mdc_dlx);
    objstruc.procAction(&visitor_yys); //将一个访问者对象(visitor_yys)应用到一批元素上,以实现对一批元素进行同一种(营养方面的)操作

    return 0;
}

3. 访问者模式 UML 图

访问者模式 UML 图

UML 图解析

访问者模式的 UML图中包含如下5种角色。

  • Visitor (抽象访问者):为对象结构中的每个元素子类(例如M_asplcrpM_fftdnhspM_dlx)声明一个访问操作(以Visit开头的方法)。通过这些操作的名称或参数类型,可以明确知道要访问的元素子类的类型。具体的访问者子类需要实现这些访问操作。此处指的是Visitor类。
  • ConcreteVisitor (具体访问者):实现由抽象访问者声明的每个访问操作。每个操作用于访问对象结构中的一种特定类型的元素。这里指的是Visitor_SFRYVisitor_QYRYVisitor_YYS类。
  • Element (抽象元素):定义了一个Accept方法,该方法通常接受一个指向抽象访问者类型的指针作为形参。这里指的是Medicine类。
  • ConcreteElement (具体元素):实现Accept方法,在该方法中调用访问者子类中的访问操作(以Visit开头的方法),以便访问者能够对元素执行操作。这里指的是M_asplcrpM_fftdnhspM_dlx类。
  • ObjectStructure (对象结构):包含多个元素的集合,用于存储元素对象并提供遍历其内部元素的接口,通常用于对一组元素执行统一操作。

4. 访问者模式的优点

  1. 增加新操作容易:可以通过添加新的访问者类来增加新的操作,这符合开闭原则,允许系统易于扩展和维护。
  2. 聚合操作:访问者模式使得可以将相关的操作集中到一个访问者中,而不是分散在各个元素类中,这有助于组织和集中管理相关操作,减少系统的复杂性。
  3. 累积状态:访问者可以在访问元素时累积状态,而不需要将这些状态存储在元素之中,这有助于避免元素类变得臃肿,同时可以轻松地添加新的累积逻辑。

5. 访问者模式的缺点

  1. 破坏封装:访问者模式通常需要元素暴露一些原本应为私有的实现细节给访问者,这违反了面向对象的封装原则。
  2. 难以维护:如果经常添加新的元素类,每次添加都需要修改所有访问者类以添加新的访问操作,这可能导致代码难以维护。
  3. 复杂度增加:使用访问者模式会增加系统的复杂度,学习和理解系统的难度增加,特别是在具有大量元素和访问者的系统中。

6. 访问者模式适用场景

  1. 操作频繁变化:当系统的数据结构相对稳定,但操作经常变化时,使用访问者模式可以使这些操作易于修改和扩展。
  2. 需要对复合对象执行多种不相关的操作:当需要对一组对象结构执行很多不相关的操作时,而你又希望避免这些操作“污染”这些对象的类。
  3. 区分多种类型的元素:当一个对象结构包含多种类型的元素,并且你希望对这些元素执行一些依赖于其具体类型的操作时。

总结

在实际应用中,访问者模式特别适用于数据结构相对稳定,但操作经常变化的场景,例如在多种不同类型的对象上执行多种不相关的操作。通过将操作逻辑封装在访问者中,可以保持元素类的简洁并易于管理和扩展。总之,访问者模式是一种非常有用的设计工具,可以有效地帮助开发者管理和扩展复杂系统中的操作。

完整代码

#include <iostream>
#include <list>

using namespace std;

class Visitor; //类前向声明
//药品父类
class Medicine
{
public:
    virtual void Accept(Visitor* pvisitor) = 0;//这里的形参是访问者父类指针
public:
    virtual string getMdcName() = 0;  //药品名称
    virtual float getPrice() = 0;     //药品总价格,单位:元
};


//药品:阿司匹林肠溶片
class M_asplcrp : public Medicine
{
public:
    virtual string getMdcName()
    {
        return "阿司匹林肠溶片";
    }
    virtual float getPrice()
    {
        return 46.8f;    //为简化代码,直接给出药品总价而不单独强调药品数量了,比如该药品医生给开了两盒,一盒是23.4,那么这里直接返回两盒的价格
    }

public:
    virtual void Accept(Visitor* pvisitor);

};
//药品:氟伐他汀钠缓释片
class M_fftdnhsp : public Medicine
{
public:
    virtual string getMdcName()
    {
        return "氟伐他汀钠缓释片";
    }
    virtual float getPrice()
    {
        return 111.3f;    //三盒的价格
    }

public:
    virtual void Accept(Visitor* pvisitor);

};
//药品:黛力新
class M_dlx : public Medicine
{
public:
    virtual string getMdcName()
    {
        return "黛力新";
    }
    virtual float getPrice()
    {
        return 122.0f;    //两盒的价格
    }

public:
    virtual void Accept(Visitor* pvisitor);

};

//----------------
//访问者父类
class Visitor
{
public:
    virtual ~Visitor() {} //做父类时析构函数应该为虚函数

    virtual void Visit_elm_asplcrp(M_asplcrp* pelem) = 0;//访问元素:阿司匹林肠溶片
    virtual void Visit_elm_fftdnhsp(M_fftdnhsp* pelem) = 0;//访问元素:氟伐他汀钠缓释片
    virtual void Visit_elm_dlx(M_dlx* pelem) = 0; //访问元素:黛力新
};

//收费人员访问者子类
class Visitor_SFRY : public Visitor
{
public:
    virtual void Visit_elm_asplcrp(M_asplcrp* pelem)
    {
        float tmpprice = pelem->getPrice();
        cout << "收费人员累计药品“" << pelem->getMdcName() << "”的价格:" << tmpprice << endl;
        m_totalcost += tmpprice;
    }
    virtual void Visit_elm_fftdnhsp(M_fftdnhsp* pelem)
    {
        float tmpprice = pelem->getPrice();
        cout << "收费人员累计药品“" << pelem->getMdcName() << "”的价格:" << tmpprice << endl;
        m_totalcost += tmpprice;
    }
    virtual void Visit_elm_dlx(M_dlx* pelem)
    {
        float tmpprice = pelem->getPrice();
        cout << "收费人员累计药品“" << pelem->getMdcName() << "”的价格:" << tmpprice << endl;
        m_totalcost += tmpprice;
    }

    //返回总费用
    float getTotalCost()
    {
        return m_totalcost;
    }
private:
    float m_totalcost = 0.0f;  //总费用
};

//取药人员访问者子类
class Visitor_QYRY : public Visitor
{
public:
    virtual void Visit_elm_asplcrp(M_asplcrp* pelem)
    {
        cout << "取药人员将药品“" << pelem->getMdcName() << "”拿给了我!" << endl;
    }
    virtual void Visit_elm_fftdnhsp(M_fftdnhsp* pelem)
    {
        cout << "取药人员将药品“" << pelem->getMdcName() << "”拿给了我!" << endl;
    }
    virtual void Visit_elm_dlx(M_dlx* pelem)
    {
        cout << "取药人员将药品“" << pelem->getMdcName() << "”拿给了我!" << endl;
    }
};

//营养师访问者子类
class Visitor_YYS : public Visitor
{
public:
    virtual void Visit_elm_asplcrp(M_asplcrp* pelem)
    {
        cout << "营养师建议:“多吃粗粮少吃油,可以有效的预防血栓”!" << endl;
    }
    virtual void Visit_elm_fftdnhsp(M_fftdnhsp* pelem)
    {
        cout << "营养师建议:“多吃蘑菇、洋葱、,猕猴桃,可以有效的降低血脂”!" << endl;
    }
    virtual void Visit_elm_dlx(M_dlx* pelem)
    {
        cout << "营养师建议:“多出去走走呼吸新鲜空气,多晒太阳,多去人多热闹的地方,保持乐观开朗的心情”!" << endl;
    }
};


//各个药品子类Accept方法的实现体代码
void M_asplcrp::Accept(Visitor* pvisitor)
{
    pvisitor->Visit_elm_asplcrp(this);
}
void M_fftdnhsp::Accept(Visitor* pvisitor)
{
    pvisitor->Visit_elm_fftdnhsp(this);
}
void M_dlx::Accept(Visitor* pvisitor)
{
    pvisitor->Visit_elm_dlx(this);
}

//-------------

//对象结构
class ObjectStructure
{
public:
    //增加药品到药品列表中
    void addMedicine(Medicine* p_mdc)
    {
        m_mdclist.push_back(p_mdc);
    }

    void procAction(Visitor* pvisitor)
    {
        for (auto iter = m_mdclist.begin(); iter != m_mdclist.end(); ++iter)
        {
            (*iter)->Accept(pvisitor);
        }
    }
private:
    list <Medicine*> m_mdclist;  //药品列表
};


int main()
{

    Visitor_SFRY visitor_sf; //收费人员访问者子类,里面承载着向我(患者)收费的算法
    M_asplcrp mdc_asplcrp;
    M_fftdnhsp mdc_fftdnhsp;
    M_dlx mdc_dlx;

    //各个元素子类调用Accept接受访问者的访问,就可以实现访问者要实现的功能
    mdc_asplcrp.Accept(&visitor_sf); //累加“阿司匹林肠溶片”的价格
    mdc_fftdnhsp.Accept(&visitor_sf);//累加“氟伐他汀钠缓释片”的价格
    mdc_dlx.Accept(&visitor_sf);     //累加“黛力新”的价格

    cout << "所有药品的总为:" << visitor_sf.getTotalCost() << ",收费人员收取了我的费用!" << endl;

    //----
    Visitor_QYRY visitor_qy; //取药人员访问者子类,里面承载着向我发放药品的算法
    mdc_asplcrp.Accept(&visitor_qy); //我取得“阿司匹林肠溶片”
    mdc_fftdnhsp.Accept(&visitor_qy);// 我取得“氟伐他汀钠缓释片”
    mdc_dlx.Accept(&visitor_qy);     //我取得“黛力新”

    //-----
    Visitor_YYS visitor_yys;  //营养师访问者子类,里面承载着为我配置营养餐的算法
    mdc_asplcrp.Accept(&visitor_yys); //营养师针对治疗预防血栓药“阿司匹林肠溶片”给出的对应的营养餐建议
    mdc_fftdnhsp.Accept(&visitor_yys);//营养师针对降血脂药“氟伐他汀钠缓释片”给出的对应的营养餐建议
    mdc_dlx.Accept(&visitor_yys);     //营养师针对治疗神经紊乱药“黛力新”给出的对应的营养餐建议

    //---------
    ObjectStructure objstruc;
    objstruc.addMedicine(&mdc_asplcrp);
    objstruc.addMedicine(&mdc_fftdnhsp);
    objstruc.addMedicine(&mdc_dlx);
    objstruc.procAction(&visitor_yys); //将一个访问者对象(visitor_yys)应用到一批元素上,以实现对一批元素进行同一种(营养方面的)操作

    return 0;
}

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

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

相关文章

spring security 记住我在web和前后端分离如何使用

一、传统web开发准备工作 如果不懂原理的话&#xff0c;去看上一篇文章&#xff1a;CSDNhttps://mp.csdn.net/mp_blog/creation/editor/141716695 导入需要的依赖包&#xff0c;在传统web页面开发比较简单&#xff0c;我们设置只需要在页面请求参数加上一个remember-me 即可&a…

Linux-gcc/g++使用

文章目录 概念gccg 编译过程预处理(进行宏替换)编译&#xff08;生成汇编&#xff09;汇编&#xff08;生成机器可识别代码&#xff09;连接&#xff08;生成可执行文件或库文件&#xff09;函数库 gcc选项 概念 Linux中的gcc和g是GNU Compiler Collection&#xff08;GNU编译…

RESP图形化界面远程连接虚拟机Redis教程

参考优质大佬文章&#xff1a; Redis安装以及RESP连接Redis服务器_resp 连接-CSDN博客 《Redis&#xff1a;小白入门》RESP远程连接问题_redis配置文件更改为可以远程连接-CSDN博客 目录 环境 第一步&#xff1a;修改redis配置文件 第二步&#xff1a;关闭Linux防火墙 第三…

功能需求文档-自适应巡航控制ACC

本文以特斯拉Model3为例&#xff0c;展示如何撰写其主动巡航控制功能的功能需求文档&#xff1b;详情请参照用户手册 功能概述 主动巡航控制(ACC)是指系统实时监控车辆前方行驶环境&#xff0c;在设定的速度范围内&#xff0c;通过控制油门和制动&#xff0c;自动调整行驶速度…

Mybatis 潦草笔记

准备工作&#xff08;创建springboot工程、数据库表、实体类&#xff09;引入Mybatis的相关依赖&#xff0c;配置Mybatis&#xff08;数据库连接信息&#xff09;编写SQL语句&#xff08;注解/XML&#xff09; 创建springboot工程 选中两项 MyBatis Framework&#xff1a;My…

分支和循环(上)

目录 1. if语句 1.1 if ​1.2 else 1.3 分支中包含多条语句 1.4 嵌套if 1.5 悬空else问题 2. 关系操作符 3. 条件操作符 4. 逻辑操作符 4.1 逻辑取反操作符 4.2 逻辑与运算符 4.3 逻辑或运算符 4.4 连续:闰年的判断 4.5 短路 5. switch语句 5.1 if语句和switch…

28. 双耳配对 - 配置

1. 概述 通过MAC地址的最后一位的奇偶来判断左右耳 2. 验证 右耳:奇数(主耳)-》BT ADDR: 12:42:22:34:34:6d 左耳:偶数(从耳)-》BT ADDR: 12:42:22:34:34:6c

K8S - 理解volumeMounts 中的subpath

在上一篇文章中 springboot service如何动态读取外部配置文件 介绍了springboot 中如何实时读取外部配置文件的内容 部署在K8S 接下来我把它部署在k8s 首先&#xff0c; 我们把配置文件放入项目某个目录 这步部是必须的&#xff0c; 毕竟我们要引入是项目外部的文件&#xf…

TI DSP TMS320F280025 Note9:GPIO输入输出与外部中断功能原理与应用

TMS320F280025 GPIO输入输出与外部中断功能原理与应用 文章目录 TMS320F280025 GPIO输入输出与外部中断功能原理与应用GPIO原理输入输出模式的共同特性1. 复用设置2. 内部上拉设置3. GPIO状态读取 对于输出模式输出电平设置开漏输出设置 对于输入模式极性设置采样类型不同步(异…

CSS3换装达人原理

引言 换装或者是换皮肤是常见的行为&#xff0c;我们可以先看下效果&#xff1a; 选择不同的颜色&#xff0c;就可以秒变人物服装的颜色&#xff0c;原理其实非常简单 实现步骤 主要分为三步&#xff0c;即素材的提供、布局样式、动态控制 图片提供 提供两张图片&#xff…

每日OJ_牛客_红与黑(简单dfs)

目录 牛客_红与黑&#xff08;简单dfs&#xff09; 解析代码 牛客_红与黑&#xff08;简单dfs&#xff09; 红与黑__牛客网 解析代码 循环接收每组用例&#xff0c;对于每组用例进行如下操作&#xff1a; 1. 找到‘’所在的位置&#xff0c;即起始搜索的点 2. 使用DFS搜索地…

20240831-PostgreSQL小课持续更新

PostgreSQL 小课专栏介绍 PostgreSQL 小课目前已累积了近 21 万字。小课最新的大纲&#xff1a; 目前已完成大概 95% 的进度&#xff1a; (venv312) ➜ mypostgres git:(dev) sh scripts/word_statistics_pg_style.shFilename …

【微服务】限流、熔断和降级(持续更新中~)

1、限流 1.1 什么是限流 限流&#xff08;Rate Limiting&#xff09;是一种常用的技术手段&#xff0c;用于控制系统对资源的访问速率&#xff0c;确保系统的稳定性和可靠性。在分布式系统、Web服务、API接口等场景中&#xff0c;限流尤为重要。通过限制请求的频率或数量&…

uniapp u--input实现select下拉列表 input点击事件

背景&#xff1a; 技术框架&#xff1a; uniapp框架(vue2语法)uView组件库。 通过form表单实现数据列表的“查询”功能。注意&#xff1a; 1、<u--form>内部嵌套<u-form-item>&#xff0c;<u-form-item>内部嵌套<u--input>表单组件。 2、H5浏览器端&am…

华为 HCIP-Datacom H12-821 题库

有需要题库的可以看主页置顶 1.MSTP 有不同的端口角色&#xff0c;对此说法不正确的是&#xff1a; A、MSTP 中除边缘端口外&#xff0c;其他端口角色都参与 MSTP 的计算过程 B、MSTP 同一端口在不同的生成树实例中可以担任不同的角色。 C、MSTP 域边缘端口是指位于 MST 域的边…

QT实战项目之音乐播放器

项目效果演示 myMusicShow 项目概述 在本QT音乐播放器实战项目中&#xff0c;开发环境使用的是QT Creator5.14版本。该项目实现了音乐播放器的基本功能&#xff0c;例如开始播放、停止播放、下一首播放、上一首播放、调节音量、调节倍速、设置音乐播放模式等。同时还具备搜索功…

SPR系列单点激光测距传感器|模组之RS485串口调试说明

SPR系列单点激光测距传感器|模组是一款近程红外测距传感器&#xff0c;测距距离可达0-10米&#xff0c;可用于对物体进行非接触式距离测量&#xff0c;其应用场景十分广泛工业自动化&#xff1a;在生产线、传送带等工业自动化场景中&#xff0c;可以使用红外测距传感器进行物体…

Git安装及配置

Git安装 在你开始使用 Git 前,需要将它安装在你的计算机上。 即便已经安装,最好将它升级到最新的版本。 你可以通过软件包或者其它安装程序来安装,或者下载源码编译安装。 下面,我们将会介绍不同操作系统上 Git 的安装方法。 在 Windows 上安装 在 Windows 上安装 Git 的…

LangChain基础知识

这篇文档介绍了LangChain大模型应用开发框架的入门知识和核心内容&#xff0c;包括LangChain是什么、为什么需要它、典型使用场景、基础概念与模块化设计等。同时&#xff0c;还详细阐述了该框架的核心模块如标准化的大模型抽象、大模型应用的最佳实践、赋予应用记忆的能力、框…

JDBC |封装JDBCUtils|PreparedStatement|事务|批处理|数据库连接池| Blob类型数据的读写|Apache—DBUtils简介

一.概述 在Java中&#xff0c;数据库存取技术可分为如下几类&#xff1a; JDBC直接访问数据库JDO技术&#xff08;Java Data Object&#xff09;第三方O/R工具&#xff0c;如Hibernate, Mybatis 等 JDBC是java访问数据库的基石&#xff0c;JDO, Hibernate等只是更好的封装了J…