面向对象程序设计之开放-封闭原则(OCP)

来源:互联网 发布:php授权 编辑:程序博客网 时间:2024/04/29 03:01

所谓开放就是一个模块的功能是可以扩展的,是可以随时满足外部需求的变化;所谓封闭就是在模块功能扩展的同时,我们不必去改动原有模块的代码,不必去破坏原有模块的完整性,我们所要做的只是在模块之外添加一些代码。

要满足这个原则的关键方法就是抽象,将模块的功能抽象化,例如我们现在需要开发一个模块去读入外部设备输入的数据并把数据显示出来,刚开始的时候,需求只是要求从键盘读入,于是我们实现我们的模块

void module(){int data = ReadFromKB();//从键盘读入ShowData(data);//显示数据}

可是过了几天,需求变了,说是要求模块也可以从其他非键盘读入数据,好吧,只能改动module模块了,


void module(int flag){  int data = flag? ReadFromKB() : ReadFromOther();//读入数据  ShowData(data);//显示数据}

好吧,模块的接口居然发生了变化,模块的内部也被改动了,虽然对你来说很容易,但是你有没有发现,整个项目还有很多其他地方都用到了module模块,你这样轻松的将module的接口一改,其他用到了module的地方可就不能工作了,于是你发现整个程序都得改动,真可谓是牵一发而动全身。
至此我们发现引起module发生变动的原因是读数据的方式这个行为,所以我们想能不能将读数据这个行为给抽象化,使其与模块接口无关。这样无论我读数据的方式怎么变,从哪儿读入,module模块可以不用丝毫的改动。
这个时候充分运用c++的特性了,虚函数,抽象类。我们定义一个读数据的抽象类:
class Reader{public:virtual int read() = 0;//纯虚函数,Reader为抽象类,不能实例化};


重写module模块
void module(Reader &rd){  int data =  rd.read();//从键盘读入数据  ShowData(data);//显示数据}


模块的参数为抽象类Reader的一个引用,也可以是指针,但是不能是实例.
好了,现在我们想从键盘读入数据了,可以这样写
class ReadKB : public Reader{public:virtual int read(){return 11;//这里插入从键盘读书数据的代码}}

为了让模块工作,实例化一个ReadKB对象
ReadKB rdkb;
Reader &r = rdkb;
module(r);//模块开始工作了从键盘读书数据
那我要从其他地方读入数据怎么办,再次重写基类Reader的read函数
class Readother : public Reader{public:virtual int read(){return 22;//这里插入从其他设备读书数据的代码}}


为了让模块工作,实例化一个Readother对象
Readother  rdot;
Reader &r = rdot;
module(r);//模块开始工作了从其他设备读书数据
总之,经过这样的抽象化,无论从设备读书数据,整个模块的接口及其内部是不发生变化的,这就是封闭,我们只需要增加一些代码便可以满足需求的变化,这就是开放。
从上面的一个例子我们可以看出,遵循OCP原则,也就是要求我们将那些容易引起模块发生变化的行为抽象化,所以在软件开发初始,我们要有预见性的预测哪些行为将会是有变化的。

参考资料<<敏姐软件开发:原则、模式与实践>>


0 0