从长远来看,越简单的代码会变的越复杂。在这个迭代后期,我们的开发者在sendReminderMessage方法中添加了一些更复杂的逻辑(预处理用户名和校验邮箱地址)。
我们现在有了sendReminderMessage方法的新版本(虽然是一个很简陋的验证系统),使得(曾经相似的)UserReminderService变得相当不同。
用来给向用户发送消息的过程发生了变化 (需要进行校验).
由于该过程没有包含在User类内部,我们就必须追踪它在所有不同形式下的所有实现,然后对它们进行修改. 假设我们意识到
SignupVerificationService也需要校验,然后我们为它添加了校验,
我们仍然需要一种能够重复使用这端校验代码的方法.在需要校验的情况下,我们可能会把方法封装到mailService中,但对于其他的逻辑,比如用户姓
名格式化,已经被加入到不同的helper/service类中了,该怎么办呢?.
这些代码可能会被多个service类所需要,也可能只有一个service需要.
第五步: 灾难来临
不能被很容易的移入一个外部依赖(比如,mail service)的代码就不得不被service类所共享.
将这些方法放进一个超类中供两个service共享貌似是个好主意.
我们可以看到那样形成的代码对原始的domain没有影响. 不再是User,Message和MailService,我们最终以一群奇怪的生物,就像
AbstractUserService, UserValidationService, UserReminderService等等告终.
很快,我们就很难知道新的代码真正属于哪部分,也很难知道需要写那些新代码的方法所处的位置是否会影响它的使用或者重用.
5 | ------------------------------------ |
7 | UserValidationService UserReminderService |
与此同时另一个开发者也写了另一个service,这个service是用来给某个Department实体(同样也使用email地址)发送消息的.这
位开发者想要使用AbstractUserService中的邮箱验证和名字格式化功能,但他的代码是为Departments服务的,而不是
Users,因此,代码结构中另一层又出现了:AbstractEntiryService.
哪里错了呢?
我们已经失去了对我们程序结构的控制,我们的开发团队开始发现很难再写出干净的代码. 我们的类需要比实际需求更多的公共方法来维护复杂的类关系
。
总结
通过贫血的领域模型来保持代码结构整洁并且可维护是当然不可能的.然而,当我们能够使用充血领域模型的时候,维护代码并且保持类接口简洁就变得非常容易了.
03 | private IMailService mailService; |
04 | private IMessageService messageService; |
06 | private final String name; |
07 | private final String emailAddress; |
09 | public User( final String name, final String emailAddress) { |
11 | this .emailAddress=emailAddress; |
14 | public void sendReminderMessage() { |
15 | deliverMessage( this .messageGeneratorService.generateReminderMessage( this .getName)); |
18 | public void sendVerificationEmail() { |
19 | deliverMessage( this .messageGeneratorService.generateVerificationMessage( this .getName)); |
23 | private void deliverMessage( final String message) { |
24 | if (isEmailAddressValid(user.getEmailAddress()) { |
25 | this .mailService.sendMessage(user.getEmailAddress(), reminderMessage); |
29 | public String getName() { |
注意,我们不再需要email地址的get方法,而且,如果你能原谅我玩数字游戏,我们增加了两个User类的公共方法二不是引入两个(至少)额外的类. 当我们在适当的对象上执行方法的时候比在一个不自然的service对象上执行方法看起来更直观.
MailService和MessageServices仍被允许留在系统中因为它们的角色很明确.
传送邮件是一个清晰的架构问题,应该被从领域对象中通过接口(IMailService)抽象出来.生成消息应该被如何抽象/封装可能是更值得商榷的,但
这篇文章就会比我与其的更长了.
我希望你会喜欢这篇文章.