之前一直有一个疑惑,就是在代码中经常会遇到这样的情况。为了做某件事情或者实现某个功能,需要组多的前置信息或者参数,那么这些参数是传入进去还是由下层的类自己去获取? 也就是经常出现,A->B->C->(D&E)->F.... 这样的依赖链。像这样情况,很不利于诸如B,C,D,E这些类的重用(通用)。在采用“自顶向下设计”的方式中,比较容易出现这样的情况。(特别声明,这里不是说不要采用“自顶向下设计”的方式)。今天在从一个项目里移植代码到另一个项目里的时候,又确切的遇到这样的问题了。想了想,感觉这样的代码还是有一些问题的,但是又道不出具体的理由。
例如:
如果我们想将一条曲线添加到一个部件或图形上,而曲线的点数据存储在一个文件中。
class Client
{
void addCurve()
{
CurveDrawer drawer(getFileName());
drawer.draw();
}
std::string getFileName();
};
而槽糕的是,某些情况下从文件里读出来的数据点需要再做一个转换才能直接被使用,于是这里就有两个选择,
1)在类CurveDrawer 中调用 CoordConvertor 转换后再传给CurveItem.
2)直接将从 文件里读出来的数据点传给CurveItem,由CurveItem自己再调用CoordConvertor 转换后再使用。
在自顶向下的设计中,大多数情况下会不自不觉的采用2)。
而一旦出现这种情况,CurveDrawer 和CurveItem就很难被重用(通用)。如果说CurveDrawer 会比较少的需要被重用,
那CurveItem需要被重用的需要和理由应该是非常充分的。但是因为它还依赖于CoordConvertor,所以其实其仍然很难被重用。
打住!你肯定会说我想多了,再想多就有过度设计的嫌疑了。是的,我承认,我也认为似乎有一点这样的嫌疑。(是不是啊?)
但是,我又真心觉得让 CurveItem能够被重用其实一点也不过分。
我只是觉得目前这样的设计确实不够。因为目前的CurveDrawer 类和 CurveItem不能够经得住考验,一旦我的数据不是从文件而来,而是从数据库或者别的模块传入?那该怎么办?更有可能,在有些情况下,客户端拿到的数据点可能不需要经过转换即被直接使用(这时候CurveItem 得添加if判断了,讨厌!)。
那么,问题出在哪里?
1)是应该这样设计,在变化来临的时候再去重构?还是在这样的场合可以提前预知,适当的预构?
2)或者说目前这样的设计其实已经有严重的代码臭味了?因为其每个类都不独立,有很强的相互依赖,从单一职责原则来讲,也有很大问题,
例如,CurveDrawer 至少有“读取文件”和“绘制曲线”两个职责,CurveItem有“转换坐标点” 和 “渲染点”两个职责。
3)从依赖注入的角度来说,像上述情况应该由client类读取文件,再根据需要转换坐标,然后直接将数据点塞给CurveDrawer 类,也就是说,
CurveDrawer (或者至少是CurveItem )应该由现在的接收文件名称变为接收数据点序列——这样CurveDrawer 或CurveItem类就会变得比较通用了。
4)如果这样,那么客户端代码就会显得庞大臃肿些,是不是又违反了“尽量让客户代码易用,减轻客户代码工作”的原则?
一点体会,记录下来,继续悟!
原文链接:https://www.f2er.com/javaschema/284088.html