从一个网上找的例子说起:
定义了一个ILog接口,用于记录日志文件,它有一个对外接口WriteLog用于记录日志
这些日志可以记录到磁盘上(FileLog)或者数据库上(DBLog),或者其它的什么地方;后来,你又发现需要一个StdOutLog,于是你又继承了一个StdOutLog类。
各种派生类:DBLog, FileLog, StdOutLog不同的Log创建不同的对象。但对于程序来说他们都是ILog,程序中使用该日志功能的方法都是ILog->WriteLog(),对于日志类的不同具体实现不影响你客户端的已有代码。
版本一
1、如果我们用面向过程的方法,直接针对不同的实现都分别写一个write函数,eg:void write_dblog()
2、接着,用户要求改用文件来实现,你又得写一个write_filelog()函数,关键是接下来你得把客户端程序中所有调用write_dblog的代码都改成write_filelog()
3、对于write_stdoutlog同样是上面的问题
版本二
这下,我们感觉相当的不爽,改成用宏定义来实现
#define write_log write_stdoutlog
好了,以后再怎么改,我们的程序只需要修改宏就好了。
版本三
过了一段时间,用户老是要频繁的修改记录方式,每次修改宏定义后,我们又要重新编译,
为了避免重新编译,我们现在改用dll。我们把不同写日志的函数都叫做 write_log,然后不同的dll(db.dll,file.dll,stdout.dll)根据不同需要去实现write_log函数
最后,我们把write_log 这个函数导出。这样以来,每次用户要更改记录方式的时候,我们可以直接根据需要去替换这个dll库,而不用重新修改甚至重新编译用户的代码。
(感叹dll的神奇和伟大)
版本四:
又过了一段时间,用户又提出了许多需求, 我们把他们叫做:function1(),function2(),function3()......function100()
这下麻烦了,由于使用dll,我们需要导出dll中的函数,并用指向函数的指针来记录他们,100个需求对应100个函数,都要我们在用户程序中用指针的方式记录下来,对于这个工作量 我只能表示"呵呵"。
好了,接着改。用面向对象的方法来解决:
创建一个接口
class ILog
{
virtual void write_log() = 0;
virtual void function1() = 0;
virtual void function2() = 0;
...
virtual void function100() = 0;
};
然后在DB.dll和 File.dll中,实现这个接口
class DBLog : public ILog
{
virtual void write_log() {.....};
virtual void function1() {...};
virtual void function2() {...};
...
virtual void function100() {.....};
};
class FileLog : public ILog
{
virtual void write_log() {.....};
virtual void function1() {...};
virtual void function2() {...};
...
virtual void function100() {.....};
};
最后,你再让这些dll文件只导出一个获取具体实现类的接口: ILog * create_log_object();
,这样用户程序里只需要保存一个,ILog * pLog 类型的指针。
其他的地方只需要写pLog->write_log() 、pLog->function1() 。。。。。,看到没有这样用户代码段里就不需要再去记录100多个函数指针了。我们程序的灵活性进一步提高!!!!!