上节简单讨论了下数据的流转方式,从最基本的方面进行讨论,然而,这最基础的知识点,往往被视而不见,不加细致的分析,反而去够摸比较飘的东西。关于数据及数据流转方式,还有很多方面要去考察,以后再慢慢谈。我写的每篇博客,漏洞很多,问题也很多,可惜看的人很少,没人关注,也没有人指出错误或者不对的地方来。
今天谈谈对象的依赖关系。同样从最基础的知识点谈起。先谈谈两个对象间的关系。任何一个对象,不是被其他对象所依赖,就是依赖其他对象。有一个实际情况要注意,对象的实例的使用方式,都是在一个函数里,都是在某函数中调用对象的方法,至于这个函数,是全局的,是某个对象的方法,都一样。
关于到底是被其他对象依赖,还是其他对象依赖自己,这个取舍,有的时候不那么显而易见,因为两个方向都可以。对象之所以依赖其他对象,其中的一个原因,就是前节讨论过的,希望从该对象获取数据;当然还有其他理由,比如希望自己的数据被另一个对象进行处理加工。还是一个方面一个方面的进行讨论吧。
继续上节的例子,需求是这样的:
有一个BTDownloader,下载的功能已经完成,内部保存了一些状态信息,如下:
class BTDownloader
{
double rate,speed,downloaded;
....
};
现在要将下载的状态信息实时的显示在一个List control中,这些功能,已经做成一个类了:
class StateShower
{
...
public:
void UpdateRate(double r);
void UpdateSpeed(double s);
void UpdateDownloaded(double d);
...
};
好了,需求有了,类也有了,注意,现在的类,仅仅是完成了自己的功能,比如BTDownloader,仅仅是完成了下载功能,并将自己的状态信息记录起来,同样地,StateShower也仅仅是去把数据更新到List Control中去。自己做自己的工作,这些基本上用不到太多的脑筋去分析。稍微麻烦的问题是,两个类如何关联起来。
如果将目光聚焦到BTDownloader上来,是它依赖StateShower吗?这么一来,改变就类似上节的主动推的例子,如下:
BTDownlaoder::OnDownlaod(...)
{
//计算得到rate,speed,downloaded,现在需要把数据推出去
StateShower* shower = get_shower();
shower ->UpdateRate( newrate);
shower ->UpdateSpeed( newspeed);
shower ->UpdateDownloaded( newdownloaded);
}
如此设计有问题否?当然没有,完全满足了需求,是一个很好的设计。至于BTDownloader对象实例被谁拥有,也就是被谁依赖,还是说依赖其他对象,同样可以按照从基础问题分析的方法进行分析而得到。
当然,也有另一种设计,那就是BTDownloader被StateShower依赖,也就是StateShower依赖BTDownloader。这样一来,就是上节所讲的被动拉模式了。
不过想一想,将BTDownloader放在StateShower中,然后来一个定时器去向BTDownloader要数据,根据以往经验,这个设计比较傻,应该放弃,有兴趣的,可以自行去完成。既然不放在StateShower中,那放在哪里呢?比如放在主窗口类中?在主窗口类的定时器事件中这么处理:
MainWindow::OnTimer(...)
{
StateShower* shower = get_shower();
BTDownloader* downloader = get_downloader();
shower->UpdateRate( downloader->getRate() );
....
}
虽然BTDownloader不是被StateShower依赖,也是被其他类所依赖了。这样设计有问题否?当然也没有问题了。
对于上面的需求,有人说这两个设计不好么?只要能满足需求的设计,就是好设计。这个时候,我不知道如何应用上设计模式,因为这里根本不需要设计模式。我猜,肯定有同学指出,为什么不做成观察者模式呢?为什么不让BTDownloader依赖一个观察者接口呢?
答案是过度设计了。要搞成观察者模式,就要搞出好多类来,何必如此麻烦呢?用观察者模式,实际上是在预测未来的需求变化为需要将下载的状态信息换一种方式表现,比如,写到log文件中去。但是未来谁能准确预测出来?为什么要为看不见的未来做出用不到的设计呢?等到真正的需求过来的时候,根据需求进行变化,不是很好吗?何苦折磨自己去做无用功呢?
需求开始变化了:经过实际检验发现BTDownloader在下载小文件的时候,速度反而不高,于是增加了一个新的文件下载方式ftp下载,同样地,ftp下载的功能也完成了,如下:
class FTPDownloader
{
double rate,speed,downloaded;
....
};
软件既有bt下载,同样也有ftp下载,下载的时候,需要想List Control显示当前的状态,当然,也需要增加一列显示当前是什么方式下载。如此变化,将如何修改设计呢?应该谁依赖谁呢?
