多态案例:C++信息系统框架集成第三方产品

1 需求

一般的企业信息系统都有成熟的框架。软件框架一般不发生变化,能自由的集成第三方厂商的产品。假如要在企业信息系统框架中集成第三方厂商的Socket通信产品和第三方厂商加密产品,其中Socket通信产品用于完成两点间的通信,加密产品用于数据发送时加密,以及数据接收时的解密。

下面是Socket通信产品的框架(文件名CSocketProtocol.h):

#pragma  once
#include <iostream>
using namespace std;

class CSocketProtocol			//该类定义了两个点消息收发的接口
{
public:
	CSocketProtocol()			
	{
		;
	}
	virtual ~CSocketProtocol() //虚析构函数的细节
	{
		;
	}
	
	//客户端环境的初始化
	virtual int cltSocketInit() = 0; 

	//客户端发报文
	virtual int cltSocketSend(unsigned char *buf /*in*/,  int buflen /*in*/)  = 0; 
	
	//客户端收报文
	virtual int cltSocketRev(unsigned char *buf /*in*/, int *buflen /*in out*/) = 0;

	//客户端释放资源
	virtual int cltSocketDestory() = 0;

};

这是一个抽象类,里面的函数都声明为了纯虚函数,析构函数之所以声明为抽象函数,是因为在多态的时候,可以通过父类指针或引用释放子类对象。

加密产品的框架如下(CEncDesProtocol.h):

#pragma  once

class CEncDesProtocol		//该类定义了加密接口
{
public:
	CEncDesProtocol()
	{		
	}
	virtual ~CEncDesProtocol()
	{
	}
	virtual int EncData(unsigned char *plain, int plainlen, unsigned char *cryptdata, int *cryptlen) = 0;	//加密
	virtual int DecData(unsigned char *cryptdata, int cryptlen, unsigned char *plain, int *plainlen) = 0;	//解密
};

CSocketProtocolCEncDesProtocol中的纯虚函数,由第三方厂商写的子类实现。

2 第三方厂商实现Socket通信产品

假如有两家公司入围了,他么的名字分别是Factory1和Factory2。

(1)Factory1

类的声明如下(文件名 CSckFactoryImp1.h):

#pragma  once

#include <iostream>
using namespace std;
#include "CSocketProtocol.h"

//厂商1定义的类,该类实现了抽象类的接口
class  CSckFactoryImp1 : public CSocketProtocol	
{
public:

	//客户端初始化
	virtual int cltSocketInit( /*out*/); 

	//客户端发报文
	virtual int cltSocketSend( unsigned char *buf /*in*/,  int buflen /*in*/); 

	//客户端收报文
	virtual int cltSocketRev( unsigned char *buf /*in*/, int *buflen /*in out*/);

	//客户端释放资源
	virtual int cltSocketDestory();

private:
	unsigned char *p;
	int len ;
};

类中有两个私有的成员变量plen,其中p用来存储报文内容首地址,len用来存储报文长度。
当指针作为函数的参数时,往往还需要一个表示长度的参数,用于防止数组越界。

类的实现如下(文件名 CSckFactoryImp1.cpp):

#include <iostream>
using namespace std;
#include "CSckFactoryImp1.h"

//客户端初始化
int CSckFactoryImp1::cltSocketInit( /*out*/)		//实现虚函数的时候,可以不加virtual
{
	p = NULL;
	len = 0;
	return 0;
}

//客户端发报文
int CSckFactoryImp1::cltSocketSend(unsigned char* buf /*in*/, int buflen /*in*/)
{
	p = (unsigned char*)malloc(sizeof(unsigned char) * buflen);
	if (p == NULL)
	{
		return -1;
	}
	memcpy(p, buf, buflen);
	len = buflen;
	return 0;
}

//客户端收报文
int CSckFactoryImp1::cltSocketRev(unsigned char* buf /*in*/, int* buflen /*in out*/)
{
	if (buf == NULL || buflen == NULL)
	{
		return -1;
	}

	*buflen = this->len;
	memcpy(buf, this->p, this->len);
	return 0;
}

//客户端释放资源
int CSckFactoryImp1::cltSocketDestory()
{
	if (p != NULL)
	{
		free(p);
		p = NULL;
		len = 0;
	}
	return 0;
}

这里解释一下各个成员函数
cltSocketInit()函数实现客户端环境的初始化,这主要是对CSckFactoryImp1类中的两个成员变量进行赋值,有点类似于构造函数,但构造函数只能在创建对象时调用,这里的初始化函数可以在创建对象后调用,某些时候可以实现“重置”的功能

cltSocketSend(unsigned char* buf /*in*/, int buflen /*in*/)用于发送报文,这里的in表示数据传递方向,参数除了可以从函数外向函数传递数据(in),还可以向外传递数据(out),例如参数为指针的时候。这里参数buf是报文字符串的首地址, buflen是要发送的报文长度,这个函数的作用是:开辟一块空间,并把报文复制到这段内存空间中。这个函数执行后,类CSckFactoryImp1的成员变量p将指向报文所在空间,len则是报文的长度。

cltSocketRev(unsigned char* buf /*in*/, int* buflen /*in out*/)用于客户端接收报文,实际就是把类中的两个成员变量的值给发送出去,通过函数参数向外传递数据。

cltSocketDestory()客户端释放资源,因为CSckFactoryImp1类中存在指针类型的成员变量,这里需要释放资源。

(2)Factory2

这里只是为了演示多个厂商入围的情形,所以Factory2提供的类,仅仅是类名与Factory1不一致,成员函数和成员变量与Factory1一致

类的声明如下(文件名CSckFactoryImp2.h)

#pragma  once
#include <iostream>
using namespace std;
#include "CSocketProtocol.h"

class  CSckFactoryImp2 : public CSocketProtocol
{
public:

	//客户端初始化 获取handle上下
	virtual int cltSocketInit( /*out*/);

	//客户端发报文
	virtual int cltSocketSend(unsigned char* buf /*in*/, int buflen /*in*/);

	//客户端收报文
	virtual int cltSocketRev(unsigned char* buf /*in*/, int* buflen /*in out*/);

	//客户端释放资源
	virtual int cltSocketDestory();

private:
	unsigned char* p;
	int len;
};

类的实现如下(文件名 CSckFactoryImp2.cpp):

#include <iostream>
using namespace std;
#include "CSckFactoryImp2.h"

//客户端初始化 获取handle上下
int CSckFactoryImp2::cltSocketInit( /*out*/)
{
	p = NULL;
	len = 0;
	return 0;
}

//客户端发报文
int CSckFactoryImp2::cltSocketSend(unsigned char* buf /*in*/, int buflen /*in*/)
{
	p = (unsigned char*)malloc(sizeof(unsigned char) * buflen);
	if (p == NULL)
	{
		return -1;
	}
	memcpy(p, buf, buflen);
	len = buflen;
	return 0;
}

//客户端收报文
int CSckFactoryImp2::cltSocketRev(unsigned char* buf /*in*/, int* buflen /*in out*/)
{
	if (buf == NULL || buflen == NULL)
	{
		return -1;
	}

	*buflen = this->len;
	memcpy(buf, this->p, this->len);
	return 0;
}

//客户端释放资源
int CSckFactoryImp2::cltSocketDestory()
{
	if (p != NULL)
	{
		free(p);
		p = NULL;
		len = 0;
	}
	return 0;
}

(3)测试

可以写一个测试文件(文件名socket_test.cpp),来对两个厂商提交的产品进行测试:

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

#include "CSocketProtocol.h"
#include "CSckFactoryImp1.h"
#include "CSckFactoryImp2.h"

//面向抽象类编程,框架实现完毕
//用于收发报文
int SckSendAndRec01(CSocketProtocol* sp, unsigned char* in, int inlen, unsigned char* out, int* outlen)
{
	int ret = 0;
	ret = sp->cltSocketInit();		//客户端初始化
	if (ret != 0)
	{
		goto End;
	}

	ret = sp->cltSocketSend(in, inlen);		//客户端发送报文
	if (ret != 0)
	{
		goto End;
	}

	ret = sp->cltSocketRev(out, outlen);	//客户端发送报文
	if (ret != 0)
	{
		goto End;
	}

End:
	ret = sp->cltSocketDestory();			//客户端释放资源
	return 0;
}


//写一个框架
int main()
{
	int ret = 0;
	unsigned char in[4096];
	int inlen;
	unsigned char out[4096];
	int outlen = 0;

	strcpy((char*)in, "aadddddddddddaaaaaaaaaaa");
	inlen = 9;


	CSocketProtocol* sp = NULL;

	//sp = new CSckFactoryImp1		//使用Factory1提供的类
	sp = new CSckFactoryImp2; 		//使用Factory2提供的类

	ret = SckSendAndRec01(sp, in, inlen, out, &outlen);
	if (ret != 0)
	{
		printf("func SckSendAndRec() err:%d \n", ret);
		return ret;
	}
	delete sp; //想通过父类指针 释放所有的子类对象的资源 ..

	cout << "hello..." << endl;
	system("pause");
	return ret;
}

3 第三方厂商实现加密产品

这里为了简便,假设加密产品只有一家公司入围(假设这家公司的名称为Hw)

(1)实现需求

他们写的类声明如下(文件名HwEncDec.h):

#pragma once
#include <iostream>
using namespace std;
#include "CEncDesProtocol.h"

class HwEncDec : public CEncDesProtocol
{
public:
	virtual int EncData(unsigned char* plain, int plainlen, unsigned char* cryptdata, int* cryptlen);
	virtual int DecData(unsigned char* cryptdata, int cryptlen, unsigned char* plain, int* plainlen);
};

类的定义如下:

#include <iostream>
using namespace std;
#include "HwEncDec.h"
#include "des.h"

int HwEncDec::EncData(unsigned char* plain, int plainlen, unsigned char* cryptdata, int* cryptlen)
{
	int ret = 0;
	//用户使用的函数
	ret = DesEnc(plain, plainlen, cryptdata, cryptlen);
	if (ret != 0)
	{
		printf("func DesEnc() err:%d \n ", ret);
		return ret;
	}
	return ret;
}

int HwEncDec::DecData(unsigned char* cryptdata, int cryptlen, unsigned char* plain, int* plainlen)
{
	int ret = 0;
	//用户使用函数des解密
	ret = DesDec(cryptdata, cryptlen, plain, plainlen);
	if (ret != 0)
	{
		printf("func DesDec() err:%d \n ", ret);
		return ret;
	}
	return ret;
}

这里导入了一个名为des.h的文件,它是对所用加密、解密算法的声明,也就是说,类在实现的时候使用了之前写过的算法。des.h代码如下:

/*********************************************************
 *  des.h
 *  用户使用des算法头文件
 *
 *********************************************************/
#ifndef _OPENDESS_H_
#define _OPENDESS_H_

#ifdef __cplusplus
extern "C" {
#endif

	//ab\0defg

	//用户使用的函数
	int DesEnc(
		unsigned char* pInData,
		int            nInDataLen,
		unsigned char* pOutData,
		int* pOutDataLen);

	//用户使用函数des解密
	int DesDec(
		unsigned char* pInData,
		int            nInDataLen,
		unsigned char* pOutData,
		int* pOutDataLen);

#ifdef __cplusplus
}
#endif

#endif

这里#ifdef __cplusplus表示:判断当前的环境是否为C++编译环境
extern "C" {...}表示:花括号中的内容按C语言的语法进行编译和链接
也就是说,这里调用了C语言编写的函数。

加密解密算法写在了des.cpp中(代码太长,有800多行,这里略过),虽然后缀是cpp,但是因为C++兼容C,所以还是可以正常使用

(2)测试

需求实现后,就是测试了,测试代码如下(socket_DecEnc_test.cpp):

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

#include "CSocketProtocol.h"
#include "CSckFactoryImp1.h"
#include "CSckFactoryImp2.h"

#include "CEncDesProtocol.h"
#include "HwEncDec.h"

//面向抽象类编程,框架实现完毕
//c函数
int SckSendAndRec_EncDec(CSocketProtocol* sp, CEncDesProtocol* ed, unsigned char* in, int inlen, unsigned char* out, int* outlen)
{
	int ret = 0;
	unsigned char data[4096];
	int datalen = 0;

	ret = sp->cltSocketInit();
	if (ret != 0)
	{
		goto End;
	}

	ret = ed->EncData(in, inlen, data, &datalen);
	if (ret != 0)
	{
		goto End;
	}
	ret = sp->cltSocketSend(data, datalen); //发送数据之前对数据加密 ..
	if (ret != 0)
	{
		goto End;
	}

	ret = sp->cltSocketRev(data, &datalen); //收到的数据是密文,需要进行解密
	if (ret != 0)
	{
		goto End;
	}
	ret = ed->DecData(data, datalen, out, outlen);
	if (ret != 0)
	{
		goto End;
	}

End:
	ret = sp->cltSocketDestory();
	return 0;
}

//写一个框架
int main()
{
	int ret = 0;
	unsigned char in[4096];
	int inlen;
	unsigned char out[4096];
	int outlen = 0;

	strcpy((char*)in, "aadddddddddddaaaaaaaaaaa");
	inlen = 9;


	CSocketProtocol* sp = NULL;
	CEncDesProtocol* ed = NULL;

	//sp = new CSckFactoryImp1

	sp = new CSckFactoryImp2; //
	ed = new HwEncDec;

	ret = SckSendAndRec_EncDec(sp, ed, in, inlen, out, &outlen);
	if (ret != 0)
	{
		printf("func SckSendAndRec() err:%d \n", ret);
		return ret;
	}
	delete sp; //想通过父类指针 释放所有的子类对象的资源 ..

	cout << "hello..." << endl;
	system("pause");
	return ret;
}

至此,加密产品也通过了测试

4 测试框架类

我们前面的测试,框架都是函数,这是C语言的思维,真正的面向对象思维,框架应该是一个类,我们来实现一下这个类。


#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

#include "CSocketProtocol.h"
#include "CSckFactoryImp1.h"
#include "CSckFactoryImp2.h"

#include "CEncDesProtocol.h"
#include "HwEncDec.h"

class MainOp
{
public:
	MainOp()
	{
		this->sp = NULL;
		this->ed = NULL;
	}
	MainOp(CSocketProtocol* sp, CEncDesProtocol* ed)
	{
		this->sp = sp;
		this->ed = ed;
	}

	void setSp(CSocketProtocol* sp)
	{
		this->sp = sp;
	}

	void setEd(CEncDesProtocol* ed)
	{
		this->ed = ed;
	}

public:
	int SckSendAndRec_EncDec3(unsigned char* in, int inlen, unsigned char* out, int* outlen)
	{
		int ret = 0;
		unsigned char data[4096];
		int datalen = 0;


		ret = this->sp->cltSocketInit();
		if (ret != 0)
		{
			goto End;
		}

		ret = this->ed->EncData(in, inlen, data, &datalen);
		if (ret != 0)
		{
			goto End;
		}
		ret = this->sp->cltSocketSend(data, datalen); //发送数据之前对数据加密 ..
		if (ret != 0)
		{
			goto End;
		}

		ret = sp->cltSocketRev(data, &datalen); //收到的数据是密文,需要进行解密
		if (ret != 0)
		{
			goto End;
		}
		ret = ed->DecData(data, datalen, out, outlen);
		if (ret != 0)
		{
			goto End;
		}

	End:
		ret = sp->cltSocketDestory();
		return 0;
	}

private:
	CSocketProtocol* sp;
	CEncDesProtocol* ed;

};

//写一个框架
int main()
{
	int ret = 0;
	unsigned char in[4096];
	int inlen;
	unsigned char out[4096];
	int outlen = 0;

	strcpy((char*)in, "aadddddddddddaaaaaaaaaaa");
	inlen = 9;


	MainOp* myMainOp = new MainOp;	//调用无参构造函数

	CSocketProtocol* sp = NULL;
	CEncDesProtocol* ed = NULL;

	//sp = new CSckFactoryImp1
	sp = new CSckFactoryImp2; 
	ed = new HwEncDec;

	//将第三方厂商的产品注入到框架
	myMainOp->setSp(sp);
	myMainOp->setEd(ed);

	ret = myMainOp->SckSendAndRec_EncDec3(in, inlen, out, &outlen);
	if (ret != 0)
	{
		printf("myMainOp SckSendAndRec_EncDec3() err\n ", ret);
	}

	delete sp;
	delete ed;
	delete myMainOp;

	cout << "hello..." << endl;
	system("pause");
	return ret;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值