Zhuoyu Yang 努力学习 Javascript 中...

从测试中找到更好的面向对象设计(三)

到目前为止我们还没有写任何一行代码,但是 test 让我们望而却步无法继续。很多时候大家讨厌写 test ,或者放弃决定不做 test 都是从此时开始。一开始说过,测试将会反映出我们的设计模式,那么此时我们从测试中可以发现些什么呢?

Test reflect the design.

我们严格按照业务逻辑写完的 specs ,在这里每一个 context 都意味着在我们的实现代码中会产生一个 if statement ,每一个嵌套的 context 也就意味着 if statement 的嵌套。

每一个在描述中提到的 object 就将是我们实现代码中需要与之交互作用的。

所以经过我们按照我们目前想像的业务逻辑可以画出这样一张图:

test-reflect-design

在这里我们把所有的业务都交给 EmailRepliesController#create 来做,所以就会有这样的结果。具体的问题大致如下:

  • Structural Coupling!
  • Controller 做了太多太多的事情。
  • Controller 知道了太多太多的细节。

发现问题,解决问题。越早的发现问题,我们就会越少的面临难题。在我们还没有写任何一行实现代码的时候就开始重构(Structural Refactoring),或者我更愿意称之为重新设计(Re-Design)。

在我们开始下一步的重新设计之前,我想先设想一下如果我们坚持把那个复杂的版本做完后会怎么样?当然我还记得那个时候我没有勇气去完成 test,那么如果不写 Test 直接写实现代码会怎么呢?

havenot-refactoring

看到这样的代码,我想我更没有勇气去做重构了。所以越早的发现问题,就能够越早的避免难题。

Re-Design From the Test.

对于面向对象设计模式,就是一个把整体复杂变为局部简单的过程。因为我们无法改变项目本身的业务逻辑,所以我们可以做的就是拆分整体的复杂程度,用一个个新的 Object 来达到每个对象之间的关系清晰,每个对象本身局部简单的目的。

redesign

从我们从 test 中发现的复杂程度,Controller 做了太多的事情。所以我们要求把他改变为单一只做一件事。我们不考虑它具体怎么去做验证和 Validation ,我们也不考虑它如何创建 Comment。在这里,我们只关心它是否告诉一个叫做 email handler 的 Object,并且让 email handlerhandle

什么是 email_handler ? 我希望它是一个叫做 EmailHandler 的实力。email_handler = EmailHandler.any_instance

那又如何 handle 呢?我们不关心他如何去做,我们只在乎当 post request 有效的时候,email_handler 是否接收到了这个 command 。email_handler.should_receive(:handle)

最后的 controller 实现就会如下:

controller

相关链接:

RubyConf China 2013 演讲视频

从测试中找到更好的面向对象设计(一)

从测试中找到更好的面向对象设计(二)

从测试中找到更好的面向对象设计(四)

comments powered by Disqus