设计模式之策略模式
笔者经常使用Modbus TCP和Modbus RTU通信协议,而两种的请求数据的格式不一样,故而采用策略模式来健壮整个工程项目。
- 代码示例
#ifndef MODBUS_H
#define MODBUS_H
#include <string>std::string convertToHex(unsigned char* data, int length);class Modbus
{
public:Modbus();virtual void modbusFormat() = 0;
};#endif // MODBUS_H#include "modbus.h"
#include <sstream>
#include <iomanip>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<int>(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 <stdint.h>
#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 <stdint.h>
#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 <stdio.h>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 <iostream>
#include <unistd.h>
#include <cstdlib>
#include <ctime>
#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;
}
- 效果演示