C++设计模式_07_Bridge 桥模式

news2024/11/22 6:00:27

文章目录

  • 1. 动机(Motivation)
  • 2. 代码演示Bridge 桥模式
    • 2.1 基于继承的常规思维处理
    • 2.2 基于组合关系的重构优化
    • 2.3 采用Bridge 桥模式的实现
  • 3. 模式定义
  • 4. 结构(Structure)
  • 5. 要点总结

与上篇介绍的Decorator 装饰模式一样,Bridge 桥模式也属于典型的“单一职责”模式,在特性上也与Decorator 装饰模式存在很多类似,但也存在不同得到地方。

“单一职责”模式的主要特征为:“在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任。”

1. 动机(Motivation)

  • 由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个纬度的变化。

  • 如何应对这种“多维度的变化”?如何利用面向对象技术来使得类型可以轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度?

2. 代码演示Bridge 桥模式

针对上面的理解还是需要回到代码进行理解。

2.1 基于继承的常规思维处理

下面的代码是一个简单的通信模块,实现的功能包括Login()、SendMessage()…等。

class Messager{
public:
    virtual void Login(string username, string password)=0;
    virtual void SendMessage(string message)=0;
    virtual void SendPicture(Image image)=0;

    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    
    virtual ~Messager(){}
};

然后需要进行PC平台的设计,但是由于平台的不同,需要override PlaySound()、DrawShape()、WriteText()、Connect()

class PCMessagerBase : public Messager{
public:
    
    virtual void PlaySound(){
        //**********
    }
    virtual void DrawShape(){
        //**********
    }
    virtual void WriteText(){
        //**********
    }
    virtual void Connect(){
        //**********
    }
};

类似PC平台的设计,Mobile上的设计也需要对相应的功能override

class MobileMessagerBase : public Messager{
public:
    
    virtual void PlaySound(){
        //==========
    }
    virtual void DrawShape(){
        //==========
    }
    virtual void WriteText(){
        //==========
    }
    virtual void Connect(){
        //==========
    }
};

另外我们可能会有在不同平台出“精简版”、“完美版”的需求,例如,在PC平台中class PCMessagerLite : public PCMessagerBase,其中实现了某些功能,而在class PCMessagerPerfect : public PCMessagerBase,这个时候“完美版”在实现功能时会有更多的功能内容,但是最基本的是一样,都是调用PCMessagerBase的方法。同样在Mobile平台也是有“精简版”、“完美版”的需求,虽然平台不同,但是业务功能需求也是一样的。

class PCMessagerLite : public PCMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        PCMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        PCMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        PCMessagerBase::DrawShape();
        //........
    }
};

class PCMessagerPerfect : public PCMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        PCMessagerBase::PlaySound();
        //********
        PCMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        PCMessagerBase::PlaySound();
        //********
        PCMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        PCMessagerBase::PlaySound();
        //********
        PCMessagerBase::DrawShape();
        //........
    }
};

class MobileMessagerLite : public MobileMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        MobileMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        MobileMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        MobileMessagerBase::DrawShape();
        //........
    }
};

class MobileMessagerPerfect : public MobileMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::DrawShape();
        //........
    }
};

整体代码如下:

class Messager{
public:
    virtual void Login(string username, string password)=0;
    virtual void SendMessage(string message)=0;
    virtual void SendPicture(Image image)=0;

    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    
    virtual ~Messager(){}
};


//平台实现

class PCMessagerBase : public Messager{
public:
    
    virtual void PlaySound(){
        //**********
    }
    virtual void DrawShape(){
        //**********
    }
    virtual void WriteText(){
        //**********
    }
    virtual void Connect(){
        //**********
    }
};

class MobileMessagerBase : public Messager{
public:
    
    virtual void PlaySound(){
        //==========
    }
    virtual void DrawShape(){
        //==========
    }
    virtual void WriteText(){
        //==========
    }
    virtual void Connect(){
        //==========
    }
};



//业务抽象

class PCMessagerLite : public PCMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        PCMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        PCMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        PCMessagerBase::DrawShape();
        //........
    }
};



class PCMessagerPerfect : public PCMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        PCMessagerBase::PlaySound();
        //********
        PCMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        PCMessagerBase::PlaySound();
        //********
        PCMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        PCMessagerBase::PlaySound();
        //********
        PCMessagerBase::DrawShape();
        //........
    }
};


class MobileMessagerLite : public MobileMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        MobileMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        MobileMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        MobileMessagerBase::DrawShape();
        //........
    }
};


class MobileMessagerPerfect : public MobileMessagerBase {
public:
    
    virtual void Login(string username, string password){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::DrawShape();
        //........
    }
};


void Process(){
        //编译时装配
        Messager *m =
            new MobileMessagerPerfect();
}

以上是一种编译式装配的方式,上面代码的框架不难画出,得到如下图:

在这里插入图片描述

2.2 基于组合关系的重构优化

如果将平台实现列为n的话,将业务抽象列为m的话,整体类的数目就是1+n+m*n,此处不像Decorator 装饰模式中Lite和Perfect会有组合的情况,这样就造成大量的类,并且在类中的方法也是存在重复的例如:

PCMessagerPerfect中的:

    virtual void Login(string username, string password){
        
        PCMessagerBase::PlaySound();
        //********
        PCMessagerBase::Connect();
        //........
    }

MobileMessagerPerfect中的:

    virtual void Login(string username, string password){
        
        MobileMessagerBase::PlaySound();
        //********
        MobileMessagerBase::Connect();
        //........
    }

上面的内容都是似曾相识的重复,这种重复也是结构性的重复:

以下内容都是相同的

//********
//........

不同的就是:PCMessagerBase::PlaySound();MobileMessagerBase::PlaySound();PCMessagerBase::Connect();MobileMessagerBase::Connect();

如果有Decorator 装饰模式基础的话可以发现可以使用继承转组合进行重构,例如将class PCMessagerPerfect : public PCMessagerBase { }中的父类变为数据成员class PCMessagerPerfect { PCMessagerBase* messager },声明为指针是因为指针具有多态性,相应的Mobile平台的也进行修改。

class PCMessagerPerfect  {

     PCMessagerBase* messager;
    
    public:
    
    virtual void Login(string username, string password){
        
        messager->PlaySound();
        //********
        messager->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messager->PlaySound();
        //********
        messager->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        messager->PlaySound();
        //********
       messager->DrawShape();
        //........
    }
};

class MobileMessagerPerfect {
    
    MobileMessagerBase* messager;
public:
    
    virtual void Login(string username, string password){
        
        messager->PlaySound();
        //********
        messager->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messager->PlaySound();
        //********
        messager->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        messager->PlaySound();
        //********
        messager->DrawShape();
        //........
    }
};

从上面的代码可以看到,两个类不同的地方就是PCMessagerBase* messager;MobileMessagerBase* messager;,他们两个来自于一个基类,因此可以改写为以下形式:

class PCMessagerPerfect  {

     Messager* messager; //未来运行时可以new PCMessagerPerfect();
    
    public:
    
    virtual void Login(string username, string password){
        
        messager->PlaySound();
        //********
        messager->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messager->PlaySound();
        //********
        messager->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        messager->PlaySound();
        //********
       messager->DrawShape();
        //........
    }
};

class MobileMessagerPerfect {
    
    Messager* messager; //未来运行时可以new MobileMessagerPerfect();
public:
    
    virtual void Login(string username, string password){
        
        messager->PlaySound();
        //********
        messager->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messager->PlaySound();
        //********
        messager->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        messager->PlaySound();
        //********
        messager->DrawShape();
        //........
    }
};

此时class PCMessagerPerfect和class PCMessagerPerfect已经没有什么区别了,他们的区别就是在未来运行时,编译时的代码就可以变为:

class MessagerPerfect{

     Messager* messager; //未来运行时可以new PCMessagerPerfect()等;
    
    public:
    
    virtual void Login(string username, string password){
        
        messager->PlaySound();
        //********
        messager->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messager->PlaySound();
        //********
        messager->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        messager->PlaySound();
        //********
       messager->DrawShape();
        //........
    }
};

class MessagerPerfect{
    
    Messager* messager; //未来运行时可以new MobileMessagerPerfect();
public:
    
    virtual void Login(string username, string password){
        
        messager->PlaySound();
        //********
        messager->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messager->PlaySound();
        //********
        messager->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        messager->PlaySound();
        //********
        messager->DrawShape();
        //........
    }
};

这个时候发现两个类一模一样,这个时候只需要保留一个即可,同样的MessagerLite也是如法炮制,变为如下形式:

class MessagerLite{

     Messager* messager; //未来运行时可以new PCMessagerLite()等;
    
    public:
    
    virtual void Login(string username, string password){
     
        messager->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messager->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
       messager->DrawShape();
        //........
    }
};

此时整体代码变为如下:

class Messager{
public:
    virtual void Login(string username, string password)=0;
    virtual void SendMessage(string message)=0;
    virtual void SendPicture(Image image)=0;

    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    
    virtual ~Messager(){}
};


//平台实现

class PCMessagerBase : public Messager{
public:
    
    virtual void PlaySound(){
        //**********
    }
    virtual void DrawShape(){
        //**********
    }
    virtual void WriteText(){
        //**********
    }
    virtual void Connect(){
        //**********
    }
};

class MobileMessagerBase : public Messager{
public:
    
    virtual void PlaySound(){
        //==========
    }
    virtual void DrawShape(){
        //==========
    }
    virtual void WriteText(){
        //==========
    }
    virtual void Connect(){
        //==========
    }
};

//业务抽象
class MessagerLite{

     Messager* messager; 
    
    public:
    
    virtual void Login(string username, string password){
     
        messager->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messager->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
       messager->DrawShape();
        //........
    }
};

class MessagerPerfect{

     Messager* messager; //未来运行时可以new PCMessagerPerfect()等;
    
    public:
    
    virtual void Login(string username, string password){
        
        messager->PlaySound();
        //********
        messager->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messager->PlaySound();
        //********
        messager->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        messager->PlaySound();
        //********
       messager->DrawShape();
        //........
    }
};

void Process(){
        //编译时装配
        Messager *m =
            new MobileMessagerPerfect();
}

此时可以发现 Messager* messager; //未来运行时可以new PCMessagerPerfect()等;是不成立的,这是因为class PCMessagerBase是一个抽象类。
为什么说其是抽象类呢? 因为其只override了class Messager中的部分虚函数,另外一些没有override。这个问题如何解决呢?在子类中只使用到了基类class Messager的一部分函数,里面的两个部分的函数塞在一起是不合适的,应该将其拆分开。

class Messager{
public:
    virtual void Login(string username, string password)=0;
    virtual void SendMessage(string message)=0;
    virtual void SendPicture(Image image)=0;
    
    virtual ~Messager(){}
};

//平台实现
class MessagerImp{
public:
    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    
    virtual MessagerImp(){}
};

//平台实现 n
class PCMessagerImp : public MessagerImp{
public:
    
    virtual void PlaySound(){
        //**********
    }
    virtual void DrawShape(){
        //**********
    }
    virtual void WriteText(){
        //**********
    }
    virtual void Connect(){
        //**********
    }
};

class MobileMessagerImp : public MessagerImp{
public:
    
    virtual void PlaySound(){
        //==========
    }
    virtual void DrawShape(){
        //==========
    }
    virtual void WriteText(){
        //==========
    }
    virtual void Connect(){
        //==========
    }
};



//业务抽象 m

//类的数目:1+n+m

class MessagerLite :public Messager {

    Messager* messager; //未来运行时可以new PCMessagerLite()等;
public:
    
    virtual void Login(string username, string password){
        
        messagerImp->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messagerImp->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        messagerImp->DrawShape();
        //........
    }
};



class MessagerPerfect  :public Messager {
   Messager* messager; //未来运行时可以new PCMessagerPerfect()等; 
   
public:
    
    virtual void Login(string username, string password){
        
        messagerImp->PlaySound();
        //********
        messagerImp->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messagerImp->PlaySound();
        //********
        messagerImp->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        messagerImp->PlaySound();
        //********
        messagerImp->DrawShape();
        //........
    }
};

2.3 采用Bridge 桥模式的实现

上面也是继承转组合,当做到这里已经接近完美,同样的马丁福乐重构中讲到,如果同样的子类中有通用的字段,此处即为class MessagerLite :public Messagerclass MessagerPerfect :public Messager中的Messager* messager;,那么往上提到父类Messager中,变为以下形式:

class Messager{
protected:
     MessagerImp* messagerImp;//...
public:
    virtual void Login(string username, string password)=0;
    virtual void SendMessage(string message)=0;
    virtual void SendPicture(Image image)=0;
    
    virtual ~Messager(){}
};

class MessagerImp{
public:
    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    
    virtual MessagerImp(){}
};


//平台实现 n
class PCMessagerImp : public MessagerImp{
public:
    
    virtual void PlaySound(){
        //**********
    }
    virtual void DrawShape(){
        //**********
    }
    virtual void WriteText(){
        //**********
    }
    virtual void Connect(){
        //**********
    }
};

class MobileMessagerImp : public MessagerImp{
public:
    
    virtual void PlaySound(){
        //==========
    }
    virtual void DrawShape(){
        //==========
    }
    virtual void WriteText(){
        //==========
    }
    virtual void Connect(){
        //==========
    }
};



//业务抽象 m

//类的数目:1+n+m

class MessagerLite :public Messager {

    
public:
    
    virtual void Login(string username, string password){
        
        messagerImp->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messagerImp->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        messagerImp->DrawShape();
        //........
    }
};



class MessagerPerfect  :public Messager {
    
   
public:
    
    virtual void Login(string username, string password){
        
        messagerImp->PlaySound();
        //********
        messagerImp->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messagerImp->PlaySound();
        //********
        messagerImp->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        messagerImp->PlaySound();
        //********
        messagerImp->DrawShape();
        //........
    }
};

void Process(){
    //运行时装配
    MessagerImp* mImp=new PCMessagerImp();
    Messager *m =new Messager(mImp);
}

当然需要父类提供构造函数,去初始化MessagerImp* messagerImp;字段,子类放一个构造函数去调用父类的构造函数即可,此处未写。

此时就比较完美,类的个数就变为1+n+m,但是运行时还会有n*m的功能,这里就是桥模式。

回过头来看,在第一个版本中放了不同的函数,有不同的变化方向,一个变化方向是平台实现(PC、Mobile),一个变化方向是业务抽象(Lite、Perfect),这两个不同的变化方向,带动的行为的多态的实现也应该是往不同的方向走,也就不应该放在一个类中。

这也就体现了动机(Motivation) 中提到的多维度的变化

3. 模式定义

将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。

​ ——《设计模式》GoF

4. 结构(Structure)

在这里插入图片描述

上图是《设计模式》GoF中定义的Bridge 桥模式的设计结构。结合上面的代码看图中最重要的是看其中稳定和变化部分,也就是下图中红框和蓝框框选的部分。
在这里插入图片描述

两个变化方向独立变化,而不是搅在一起变化。

5. 要点总结

  • Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自纬度的变化,即“子类化”它们。

  • Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。(推荐一个单继承配合组合的模式)

  • Bridge模式的应用一般在“两个非常强的变化维度”,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。

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

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

相关文章

Go语言进阶------>init()函数

Init()包初始化 执行优先级 Init()函数的执行优先级比main()函数的执行优先级要高,也就是说程序会优先执行Init()函数之后再执行main()函数. 代码如下 package mainimport "fmt"func init() {fmt.Println("执行了Init()函数") }func main() {fmt.Println…

【OCR】合同上批量贴印章

一、需求 OCR算法在处理合同等文件时,会由于印章等遮挡导致文本误识别。因此在OCR预处理时,有一个很重要的步骤是“去除印章”。其中本文主要聚焦在“去除印章”任务中的数据构建步骤:“合同伪印章”的数据构建。下面直接放几张批量合成后效果…

存档&改造【04】二维码操作入口设置细节自动刷新设置后的交互式网格

因为数据库中没有数据无法查看设置效果,于是自己创建了个测试数据表,用来给demo测试 -- 二维码操作入口设置 create table JM_QR_CODE(QR_CODE_ID NUMBER generated as identity primary key,SYSTEM_ID NUMBER(20) not null,IS_ENAB…

PPT课件培训视频生成系统实现全自动化

前言 困扰全动自化的重要环节,AI语音合成功能,终于可以实现自动化流程,在此要感谢团队不懈的努力和韧性的精神! 实现原理 请参照我的文章《Craneoffice云PPT课件培训视频生成系统》 基本流程 演示视频 PPT全自动 总结 过去实…

解读大模型(LLM)的token

当人们谈论大型语言模型的大小时,参数会让我们了解神经网络的结构有多复杂,而token的大小会让我们知道有多少数据用于训练参数。 正像陆奇博士所说的那样,大型语言模型为从文本生成到问题回答的各种任务提供了令人印象深刻的能力,…

css 动态点击效果

效果图 daima <body><div></div> </body> <style>div {background-color: rgb(220, 74, 98);width: 160px;height: 60px;border-radius: 40px;transition: all 0.2s linear;}div:active {transform: scale3d(0.92, 0.92, 1);} </style>

Apache RocketMQ远程代码执行

漏洞概述 Apache RocketMQ是一个分布式消息中间件&#xff0c;专为万亿级超大规模的消息处理而设计&#xff0c;具有高吞吐量、低延迟、海量堆积、顺序收发等特点。RocketMQ 5.1.0及以下版本&#xff0c;在一定条件下&#xff0c;存在远程命令执行风险。RocketMQ的NameServer&…

如何使用 CloudQuery 对 100+ 套数据库进行安全管控?

业务挑战 A 集团信息部门发展将近 10 年&#xff0c;从最初的一个 MySQL 数据库到现在鱼龙混杂什么数据库都有&#xff0c;其中仓库部门用了 PostgreSQL 做数据底座&#xff0c;历史原因问题&#xff0c;生产系统却是使用 Oracle。基于信创的需求&#xff0c;上级领导要求试点…

CAMERALINK通信应用

简述&#xff1a; Cameralink是一个全面的视频接口&#xff0c;他可以满足以前所有的传输视频的功能&#xff0c;包括通信、配置、应答、同步、以及复位等等&#xff0c;在以前简单提过一下&#xff0c;但是没有深入研究&#xff0c;其实这个通信还是比较简单的&#xff0c;在这…

uniapp vue3 静态图片引入

方法一 从新定义路径 一定看好你图片的路径 代码 <template><div class"main">Main<img :src"getImg()" alt""></div> </template><!-- 方式一 // <script setup> // let imgName logo.png // cons…

材质、纹理、贴图的区别和关联

1、材质、纹理、贴图的概念 材质&#xff08;Material&#xff09;、纹理&#xff08;Texture&#xff09;、贴图&#xff08;Texture Map&#xff09;是计算机图形学中的三个概念&#xff0c;它们之间存在关系但也有一些区别。 材质&#xff08;Material&#xff09;是描述物…

计算机竞赛 题目:基于深度学习的中文汉字识别 - 深度学习 卷积神经网络 机器视觉 OCR

文章目录 0 简介1 数据集合2 网络构建3 模型训练4 模型性能评估5 文字预测6 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的中文汉字识别 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &a…

爬虫破解:解决CSRF-Token反爬问题 - 上海市发展和改革委员会

标题:爬虫破解:解决CSRF-Token反爬问题 - 上海市发展和改革委员会 网址:https://fgw.sh.gov.cn/fgw-interaction-front/biz/projectApproval/home MD5加密:ca7f5c978b1809d15a4b228198814253 需求文档 采集数据如下所示: 解决反爬思路 这里只提供解决思路,解决反爬,…

30 数据分析(上)(业务略写可跳)|jupyter|matplotlib

文章目录 数据科学领域概述数据如何驱动运营给企业带来价值岗位关键词说明业务的商业模式 数据指标数据指标定义及常用数据指标如何选取指标分析角度计数流量导向的工具内容导向的工具用户导向的工具业务导向的工具 数据分析方法对比分析多维分析漏斗分析留存分析总结 用户画像…

基于Java的医护人员排班系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

Python教程——配置环境,再探IDE

文章目录 一、Python安装下载安装验证 二、第一个Python程序常见问题 三、Python解释器四、PyCharm工具安装和配置安装使用PyCharm基本使用 一、Python安装 下载 如果我们想要使用Python语言编写程序&#xff0c;我们必须下载Python安装包并配置Python环境&#xff0c;我们现…

如何防止重复提交订单?

重复提交原因 其实原因无外乎两种&#xff1a; 一种是由于用户在短时间内多次点击下单按钮&#xff0c;或浏览器刷新按钮导致。 另一种则是由于Nginx或类似于SpringCloud Gateway的网关层&#xff0c;进行超时重试造成的。 常见解决方案 方案一&#xff1a;提交订单按钮置灰 …

用Blender制作YOLO目标检测器训练数据

推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 本文将介绍一种非常有吸引力的机器学习训练数据的替代方案&#xff0c;用于为给定的特定应用程序收集数据。 无论应用程序类型如何&#xff0c;这篇博文都旨在向读者展示使用 Blender 等开源资源生成合成数据&#xff08;S…

一盏茶的功夫帮你彻底搞懂JavaScript异步编程从回调地狱到async/await

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 &#x1f4d8; 1. 引言 &#x1f4d8; 2. 使用方法 &#x1f4d8; 3. 实现原理 &#x1f4d8; 4. 写到最后…

Linux I/O多路复用 select poll epoll

简介 select函数 poll函数 epoll函数