装饰器模式(c++)(单一职责型模式)

“单一职责模式”的适用场景

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

场景

某一天,你的老板写一堆log类来分别打印错误信息和警告信息。

class Log{
public:
	virtual void WriteLog(const char *data) = 0;
	virtual char ReadLog(int number) = 0;
};
class ErrorLog : public Log{
public:
	virtual void WriteLog(const char *data){
	}
	virtual char ReadLog(int number){
	}
};
class WarnLog: public Log{
public:
	virtual void WriteLog(const char *data){
	}
	virtual char ReadLog(int number){
	}
};
int main(void){
	Log *warnLog = new WarnLog();
	Log *errorLog = new ErrorLog();
	
	if(Error)
		errorLog->WriteLog("某个地方发生Error");

	if(Warn)
		warnLog->WriteLog("某个地方发生Warn");

	//经过很多次调用
	
	//假装忘记delete
	return 0;
}

这时候你解决了问题,完美下班。
but 过了几天,你老板发现,这样Log打印好像对性能负担很大,于是乎要求你先用一个Buffer储存这些log,然后再合适的时间打印这些log,于是你要写下面的类

class BufferErrorLog : public ErrorLog{
public:
	virtual void WriteLog(const char *data){
		//额外的BUffer操作
		ErrorLog::WriteLog(data);
	}
	virtual char ReadLog(int number){
		return ReadLog::ReadLog(number);
	}
};
class BufferWarnLog: public WarnLog{
public:
	virtual void WriteLog(const char *data){
		//额外的BUffer操作
		WarnLog::WriteLog(data);
	}
	virtual char ReadLog(int number){
		return WarnLog::ReadLog(number);
	}
};
int main(void){
	Log *warnLog = new BufferWarnLog();
	Log *errorLog = new BufferErrorLog();
	
	if(Error)
		errorLog->WriteLog("某个地方发生Error");
	//经过很多次调用
	//在一个合适的时候一次性输出了之前所有的Log
	if(Warn)
		warnLog->WriteLog("某个地方发生Warn");

	
	//假装忘记delete
	return 0;
}

现在视乎又解决了问题,

but又过了几天,你的老板发现直接输出log有点不安全,所以他决定在输出log的时候对log进行加密操作,并且他认为直接无Buffer的输出log是简单有效的,他觉定不舍弃直接输出的类,于是乎WarnLog,ErrorLog,BufferWarnLog,BufferErrorLog 这四个类都应该有一个子类是父类的加密(CryptoWarnLog,CryptoErrorLog,CryptoBufferWarnLog,CryptoBufferErrorLog)

本来这个项目有两个类(WarnLog,errorLog),加了Buffer功能之后这个项目就有了四个类(WarnLog,ErrorLog,BufferWarnLog,BufferErrorLog),再加个加密操作之后这个项目就有了八个类,再加一个功能,这个项目就有16个类,每加一种新的功能,类的数量成指数级(2n)增长。一旦多加几个功能,一个项目100,000类都不是梦。很明显这是不合理的,这时候就需要装饰器模式。

使用装饰器模式

装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象添加功能。在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

//之前的log类,ErrorLog类和WarnLog类这里就不重写了,从Buffer开始

class DecoratorLog :public Log{
public:
	DecoratorLog(Log *log) :mLog(log){}

protected:
	Log *mLog;
};
//它是一个装饰器
class BufferLog :public DecoratorLog {
public:
	BufferLog(Log *log) :DecoratorLog (log){}
	virtual void WriteLog(const char *data){
		//额外的Buffer操作
		mLog->WriteLog(data);
	}
	virtual char ReadLog(int number){
		return mLog->ReadLog(number);
	}
};
//它是一个装饰器
class CryptoLog : public DecoratorLog {
public:
	CryptoLog(Log *log) :DecoratorLog (log){}
	virtual void WriteLog(const char *data){
		//额外的加密操作
		mLog->WriteLog(data);
	}
	virtual char ReadLog(int number){
		return mLog->ReadLog(number);
	}
};
int main(void){
	Log *warnLog = new BufferLog(new WarnLog());
	Log *errorLog = new BufferLog(new ErrorLog());
	
	if(Error)
		errorLog->WriteLog("某个地方发生Error");
	//经过很多次调用
	//在一个合适的时候一次性输出了之前所有的Log
	if(Warn)
		warnLog->WriteLog("某个地方发生Warn");

	
	//假装忘记delete
	return 0;
}

这时候,我只写了一个BufferLog类,就能实现BufferWarnLog类和BufferErrorLog 类的功能,就算再添加一个加密操作,也只是再写一个CryptoLog 类而已。这样写加几个功能,就加几个类,类的数量就是功能的数量(n)。

这样写代码有多个好处在上面的代码中没有体现

  1. 在装饰器类里面加一个setMLog方法,同一个装饰器可以重复使用。
  2. 通过xml配置文件和工厂模式,可以把装饰器的构造通过配置文件来决定,方便后续的更新。

类图

在这里插入图片描述

装饰器模式的优点:

  1. 可以轻松对已存在的对象进行修改和包装,在被装饰者的前面或者后面添加自己的行为,而无需修改原对象。

  2. 可以动态、不限量地进行装饰,可以更灵活地扩展功能。

相对地,装饰器模式有很明显的缺点:

  1. 会加入大量的小类,即使只添加一个功能,也要额外创建一个类,使得程序更复杂。

  2. 增加代码复杂度,使用装饰器模式不但需要实例化组件,还要把组件包装到装饰者中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值