【学习笔记】C/C++ 设计模式 - 模板模式

介绍说明

模板设计模式是一种非常简单的设计模式,其主要是利用了虚函数的特性实现。非常适合应用在一些算法、流程、业务逻辑是固定的形式,其中某些步骤的实现方式又无法确定下来的场景。

举例说明

以下为模拟某芯片基于串口通信的固件升级代码,可以提供一个 FirmwareUpgrade 的类用于使用者集成。考虑到跨平台,该类的串口操作接口声明为纯虚函数,由使用者自己根据所用平台实现,而不需要关注具体的升级细节。

class FirmwareUpgrade
{
protected:

	// 具体的串口操作实现延迟到子类实现
	// 在不同的平台下, 提供对应平台的串口操作实现即可
	virtual bool openSerialPort(int nBaudRate, int nDataBit, int nStopBit, int nParityBit) = 0;
	virtual bool wrtieSerialPort(void *pOutBuffer, size_t nLength) = 0;
	virtual size_t readSerialPort(void *pInBuffer, size_t size) = 0;
	virtual bool closeSerialPort() = 0;

public:

	FirmwareUpgrade() {};
	virtual ~FirmwareUpgrade() {};

	// 开始升级
	bool upgrade(const char *pFirmwareFile) {

		init();
		...
		enterUpgradeMode();
		...
		erasePartition();
		...
		updatePartition(pFirmwareFile);
		...
		verifyPartition();
		...
		resetDevice();
		...
		release();

		return true;
	}

private:

	bool sendCommand(int cmd, void *pdata, size_t size) {

		if (!wrtieSerialPort(package, sizeof(package))) {
			return false;
		}

		if(readSerialPort(package, sizeof(package))) {
			return false;
		}

		return package->done;
	}

	bool init(){
		...
		if (!openSerialPort(115200, 8, 1, 0)) {
			return false;
		}
		...
		return true;
	}

	bool enterUpgradeMode(){
		...
	}

	bool erasePartition(){
		...
	}

	bool updatePartition(const char *pFirmwareFile){
		FILE fp = fopen(pFirmwareFilel, "rb");
		...
		while (fread(buffer, sizeof(buffer), 1, fp) == 1)
		{
			if (!sendCommand(update_COMMAND, NULL, 0)) {
				fclose(fp);
				return false;
			}
		}
		...
		fclose(fp);
		return true;
	}

	bool verifyPartition() {
		...
	}

	bool resetDevice(){
		...
	}

	bool release() {
		...
		return closeSerialPort();
	}
};

如 Windows 平台开发者,只需要利用  Windows 平台下接口实现串口的打开、写入、读取、关闭四个接口即可:


class FirmwareUpgradeWin : public FirmwareUpgrade
{
private:

	virtual bool openSerialPort(int nBaudRate, int nDataBit, int nStopBit, int nParityBit)
	{

		com_handle = CreateFile("//.//COM9", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if (com_handle != INVALID_HANDLE_VALUE){
			...
		}
		...
	}

	virtual bool wrtieSerialPort(void *pOutBuffer, size_t nLength) 
	{
		if (com_handle != INVALID_HANDLE_VALUE)
		{
			DWORD NumberOfBytesWrite;
			if (!WriteFile(com_handle, buffer, length, &NumberOfBytesWrite, NULL))
			{
				DWORD error = GetLastError();
				printf("error:%d\n", error);
			}
			return NumberOfBytesWrite;
		}
	}

	virtual size_t readSerialPort(void *pInBuffer, size_t size)
	{
		if (com_handle != INVALID_HANDLE_VALUE)
		{
			DWORD NumberOfBytesRead;
			ReadFile(com_handle, buffer, length, &NumberOfBytesRead, NULL);
			return NumberOfBytesRead;
		}
		return 0;
	}

	virtual bool closeSerialPort() 
	{
		// 关闭硬件接口 
		if (com_handle != INVALID_HANDLE_VALUE)
		{
			CloseHandle(com_handle);
		}
	}

public

	bool upgrade(const char *pFirmwareFile) {
		return FirmwareUpgrade::upgrade(pFirmwareFile);
	}
};

int main()
{
	FirmwareUpgradeWin mFirmwareUpgrade;

	mFirmwareUpgrade.upgrade("d:\\xxxx.bin");

	return 0;
}

如 Linux 平台下的实现:

class FirmwareUpgradeLinux : public FirmwareUpgrade
{
private:

	virtual bool openSerialPort(int nBaudRate, int nDataBit, int nStopBit, int nParityBit)
	{

		m_fd = ::open(device_node, O_RDWR | O_NOCTTY);
		....
		tcgetattr(m_fd, &m_options);
		....
		return true;
	}

	virtual bool wrtieSerialPort(void *pOutBuffer, size_t nLength)
	{
		... 
		byte = write(m_fd, pOutBuffer, nLength));
		...
		return true;
	}

	virtual size_t readSerialPort(void *pInBuffer, size_t size)
	{
		...
		select(m_fd + 1, &fs_read, NULL, NULL, &time);
		...
		byte = read(m_fd, data, size);
		...
		return byte;
	}

	virtual bool closeSerialPort()
	{
		...
		close(m_fd);
		...
		return true
	}

public:

	bool upgrade(const char *pFirmwareFile) {
		return FirmwareUpgrade::upgrade(pFirmwareFile);
	}
};

int main()
{
	FirmwareUpgradeLinux mFirmwareUpgrade;

	mFirmwareUpgrade.upgrade("d:\\xxxx.bin");

	return 0;
}

总结说明

主要就是将差异化的抽离出来,延迟到子类实现,而固定的逻辑处理则由父类封装并提供接口。相当于定义一个模板,子类只要按照这个模板实现相应的接口,由父类反向调用子类所实现的接口,来完成具体的逻辑功能。这样使用者不需要关心具体的升级逻辑实现,只需要按照要求完成相应的接口,即可使用升级功能,从而降低复杂性,又提升了灵活性。

posted @ 2020-04-19 07:21  Love_梦想  阅读(16)  评论(0编辑  收藏  举报