Design patterns--策略模式

设计模式之策略模式

笔者经常使用Modbus TCP和Modbus RTU通信协议,而两种的请求数据的格式不一样,故而采用策略模式来健壮整个工程项目。

  • 代码示例
#ifndef MODBUS_H
#define MODBUS_H
#include 

std::string convertToHex(unsigned char* data, int length);

class Modbus
{
public:
    Modbus();
    virtual void modbusFormat() = 0;
};

#endif // MODBUS_H

#include "modbus.h"
#include 
#include 

std::string convertToHex(unsigned char* data, int length)
{
    // std::string hexString;
    // for (int i = 0; i < length; i++)
    // {
    //     hexString += (i > 0 ? " " : "") + std::to_string(data[i]);
    // }
    // return hexString;

    // std::stringstream ss;
    // ss << std::hex << std::setfill('0');
    // for (int i = 0; i < length; i++) {
    //     ss << std::setw(2) << static_cast(data[i]) << " ";
    // }
    // return ss.str();

    std::stringstream ss;
    ss << std::hex << std::setfill('0') << std::uppercase;
    for (int i = 0; i < length; i++) {
        ss << std::setw(2) << static_cast<int>(data[i]);
        if (i < length - 1) {
            ss << " ";
        }
    }
    return ss.str();
}

Modbus::Modbus()
{

}
#ifndef MODBUSRTU_H
#define MODBUSRTU_H
#include 
#include "modbus.h"

class ModbusRtu : public Modbus
{
public:
    ModbusRtu();
    void modbusFormat() override;
    void transmitRTU();

private:
    uint8_t m_slaveId;
    uint8_t m_funCode;
    uint16_t m_registerBeginAddr;
    uint16_t m_registerTotal;
    uint16_t m_crc;
    unsigned char transmitData[8];
};

#endif // MODBUSRTU_H

#include "modbusrtu.h"

// 计算CRC16校验值
static uint16_t calculateCRC16(uint8_t* data, uint16_t length)
{
    uint16_t crc = 0xFFFF;

    for (uint16_t i = 0; i < length; i++) {
        crc ^= data[i];

        for (uint8_t j = 0; j < 8; j++) {
            if (crc & 0x0001) {
                crc >>= 1;
                crc ^= 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }

    return crc;
}


ModbusRtu::ModbusRtu()
{
    m_slaveId = 1;
    m_funCode = 3;
    m_registerBeginAddr = 10;
    m_registerTotal = 50;
}

void ModbusRtu::modbusFormat()
{
    transmitData[0] = m_slaveId;
    transmitData[1] = m_funCode;

    transmitData[2] = m_registerBeginAddr >> 8;
    transmitData[3] = m_registerBeginAddr & 0xFF;

    transmitData[4] = m_registerTotal >> 8;
    transmitData[5] = m_registerTotal & 0xFF;

    m_crc = calculateCRC16(transmitData, 6);

    transmitData[6] = m_crc >> 8;
    transmitData[7] = m_crc & 0xFF;

    transmitRTU();
}

void ModbusRtu::transmitRTU()
{
    printf("[%s:%d][RTU] %s\n", __FILE__, __LINE__, convertToHex(transmitData, 8).c_str());
}
#ifndef MODBUSTCP_H
#define MODBUSTCP_H
#include 
#include "modbus.h"

class ModbusTcp : public Modbus
{
public:
    ModbusTcp();
    void modbusFormat() override;
    void transmitTCP();

private:

    uint16_t m_transactionIdentifier; //事务标识符号
    uint16_t m_protocolIdentifier; //协议标识符
    uint16_t m_dataLength; // 数据长度
    uint8_t m_slaveId;
    uint8_t m_funCode;
    uint16_t m_registerBeginAddr;
    uint16_t m_registerTotal;

    unsigned char transmitData[12];
};

#endif // MODBUSTCP_H

#include "modbustcp.h"
#include 

static uint16_t numFlag = 0;

ModbusTcp::ModbusTcp()
{
    m_slaveId = 0x01;
    m_funCode = 0x03;
}

void ModbusTcp::modbusFormat()
{
    m_transactionIdentifier = numFlag;
    m_protocolIdentifier = 0;
    m_dataLength = 0x06;

    m_registerBeginAddr = 0x0A;
    m_registerTotal = 0x32;

    transmitData[0] = m_transactionIdentifier >> 8;
    transmitData[1] = m_transactionIdentifier & 0xFF;

    transmitData[2] = m_protocolIdentifier >> 8;
    transmitData[3] = m_protocolIdentifier & 0xFF;

    transmitData[4] = m_dataLength >> 8;
    transmitData[5] = m_dataLength & 0xFF;

    transmitData[6] = m_slaveId;
    transmitData[7] = m_funCode;

    transmitData[8] = m_registerBeginAddr >> 8;
    transmitData[9] = m_registerBeginAddr & 0xFF;


    transmitData[10] = m_registerTotal >> 8;
    transmitData[11] = m_registerTotal & 0xFF;

    numFlag++;

    transmitTCP();
}

void ModbusTcp::transmitTCP()
{
    printf("[%s:%d][TCP] %s\n", __FILE__, __LINE__, convertToHex(transmitData, 12).c_str());
}
#ifndef COMMPROTOCOL_H
#define COMMPROTOCOL_H
#include "modbus.h"

class CommProtocol
{
public:
    enum e_Modbus{
        ModbusTCP = 1,
        ModbusRTU
    };

public:
    CommProtocol();

    void setModbus(Modbus* mbus);
    void requestData();

private:
    Modbus* m_Modbus;
};

#endif // COMMPROTOCOL_H

#include "commprotocol.h"

CommProtocol::CommProtocol()
{

}

void CommProtocol::setModbus(Modbus *mbus)
{
    m_Modbus = mbus;
}

void CommProtocol::requestData()
{
    m_Modbus->modbusFormat();
}
#include 
#include 
#include 
#include 
#include "modbustcp.h"
#include "modbusrtu.h"
#include "commprotocol.h"

using namespace std;

int main()
{
    ModbusTcp modTcp;
    ModbusRtu modRtu;

    CommProtocol commProtocol;

    // 设置随机数种子
    std::srand(std::time(0));
    while (true) {
        // 生成1和3之间的随机数
        int randomNumber = std::rand() % 3 + 1;
        // printf("randomNumber = %d\n", randomNumber);
        if(randomNumber == CommProtocol::e_Modbus::ModbusTCP){
            commProtocol.setModbus(&modTcp);
            commProtocol.requestData();
        }
        else if(randomNumber == CommProtocol::e_Modbus::ModbusRTU){
            commProtocol.setModbus(&modRtu);
            commProtocol.requestData();
        }
        else{
            commProtocol.setModbus(&modTcp);
            commProtocol.requestData();
        }

        sleep(2);
    }

    cout << "==Over==" << endl;
    return 0;
}

  • 效果演示
    Design patterns--策略模式_第1张图片

你可能感兴趣的:(数据结构与算法,/,设计模式,设计模式,策略模式)