几天后,新手又一次提交了一份代码。由于改动较大,新手重新创建了一个项目。在这份代码中,新手接受了我的建议,改为使用Spring提供的JdbcTemplate。包的结构也得到了一定程度的改善。这充分说明他认识到了问题所在,并能够快速准确地采取行动去纠正这些问题。但或许是我提出的问题太多,给出的建议不够具体,在新提交的这份代码中,我还是看到了一些问题,且某些问题在上一次Review代码时,我曾经提及。
来看看如下两段代码。首先,是CustomerService,它定义了目前Story要求的基本业务:
|
在CustomerService类中,调用了CustomerDAO类的相关方法:
|
这两段代码存在什么问题?
显然,我们看到CustomerService履行的职责仅仅是对调用的委派,另外还添加了事务功能,除此之外,它什么事情都没有做,接到了请求,转手就递给CustomerDAO了。再看CustomerDAO,特别关注withdrawBalance()方法,你会发现这个方法的实现其实体现了较多的业务逻辑。事实上,我们看到这个方法的名称,体现的就是业务的概念。显然,这里的职责分配是不合理的。新手明显没有深刻体会Service与Dao之间的区别。无论是传统的分层架构模型,还是DDD提出的领域层与基础设施层的分离,都表达了业务与数据访问关注点分离的原则。事实上,新手还错误地将Service类放到了database.service包中。
正确的做法应该是保证每个对象的纯洁性与单一性,让每个对象只做一件事情,只做它应该关心的事情,遵循单一职责原则。Dao是数据访问对象,那么它就应该只处理数据访问的逻辑,而对具体业务应该是“一无所知”的。一个简单的识别办法,就是不要在这个类中出现任何业务概念,它做的事情就是CRUD。
对于许多OO初学者而言,职责不清是最容易犯下的毛病。要么就是恨不得把所有内容都塞给一个类;要么就是张冠李戴,随着性子乱分配职责,全然不考虑每个对象的感受。我常常说,对象是有意识的生物,这样不尊重对象搞乱分配,迟早这些对象会造反。