Asp.net MVC tips -- 也做为 要写漂亮的代码 (2)
2009-11-03 16:44:25 来源:WEB开发网核心提示:被称为一个漂亮的asp.net MVC应用,从代码角度来看,Asp.net MVC tips -- 也做为 要写漂亮的代码 (2),我认为得满足这三点:1. 使用依赖注入框架,2. 不要直接依赖Cache,View也是需要持续被重构的,这一篇着重强调的是, HttpContext等,3. View中不要条件逻辑
被称为一个漂亮的asp.net MVC应用,从代码角度来看,我认为得满足这三点:
1. 使用依赖注入框架。
2. 不要直接依赖Cache, HttpContext等。
3. View中不要条件逻辑。
当然不只是这三点,还有很多。我个人拿它们出来,是认为这些很重要但是经常被忽视。
对于第1点,优点在于松耦合,可测试性很好。如果在Controller里面想要使用某些Service,要么new出来,要么用单例的形式,如UserService.Instance,这样想对Controller写单元测试都不容易,它和这些Service耦合太紧密,无法将这些Service替换成Stub实现。因此,松耦合是必须的。要实现这个功能,必须让依赖注入框架来创建Controller,才有可能注入依赖并组装对象。MVC里面有一个ControllerFactory的东西,可以使用来达到这个目的。
a. 写一个类,继承自DefaultControllerFactory,例如 UnityControllerFactory : DefaultControllerFactory
b. 覆盖方法GetControllerInstance,使用依赖注入框架来创建Conroller
c. 修改Global.asax.cs, 在application_Start内注册使用自己的ControllerFactory,
ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory())
d. 对Controller进行构造函数注入,例如:
public class UserController : Controller
{
public UserController(IUserService, userService, IMessageService messageService)
…
}
从现在开始,所有的Controller都是通过依赖注入框架来创建的,新增的Service就在依赖注入框架里面注册,Controller要使用哪些Service就往构造函数里加,反正框架会注入进来。
第2点, 类如HttpContext.Current.session[“xxx”] = …, HttpContext.Current.Cache.Insert…此样的代码充斥在各个角落。有问题吗?还是老问题,可测试性,可替换性。
像HttpContext这种东西,几乎是不能Mock或者Stub的,只要代码中使用了HttpContext,可以说它就没法做单元测试。为什么很多人都会这么用呢,一个原因是图方便图简单,二是没有写单元测试。要用Session直接用就好了,封装一下再用多麻烦啊,这就是图简单。
解法很简单,对HttpContext进行封装,例如ISessionPRovider, ICacheProvider,然后通过依赖注入框架,注入到Controller中去,这样的结果是代码可测试性高,而且想改变Cache机制也很方便。
意识不够。什么意识?让代码松耦合的意识。使用静态方法,静态变量,直接new依赖的对象,这些都是松耦合的反例。我们写代码的时候要规避它们。即使我们不用TDD(极端一点来说,现在不写单元测试),脑子里也要清楚记得,面向对象的法则、松耦合的一些原则等等,然后反应到代码上去。
这一点,记得好像园子里以前有人提到过。
最后一点,View中不写条件逻辑。View中一旦加入条件判断,就会使得代码特别难以维护,难以理解。如果在aspx文件中,看到以下的代码:
<% if (条件1) { %>
<div>
…
<% if(某某条件) { %>
…
<% } %>
</div>
<%} else if (条件2) { %>
…
<% } else { %>
…
<% } %>
这样的View让人很怕去改,生怕哪里改错了而自己又不知道。因为它写的太混乱,逻辑和显示穿插在一起,如果再混着一些动态的html元素,那就真的只能谁写的谁来弄。
我们可以怎样做呢?如果是比较复杂的条件逻辑,就放到Controller里面去做,然后返回不同的View。这样View又很简单,这些逻辑又可以被测试。没有谁规定,一个Action只能对应一个View。跟Class的道理一样,Class职责过多,就得进行拆分。View的逻辑过于复杂也得进行拆分。
这么拆分以后,有可能会出现几个View有重复的部分。那就具体情况具体解决了,可以使用ViewHelper,也可以把重复的东西再独立出来,不同的View来复用。记住,View是代码的一部分,不要觉得涉及到Html的部分乱就乱点。View也是需要持续被重构的。
这一篇着重强调的是,漂亮的代码有良好的可测试性。
1. 使用依赖注入框架。
2. 不要直接依赖Cache, HttpContext等。
3. View中不要条件逻辑。
当然不只是这三点,还有很多。我个人拿它们出来,是认为这些很重要但是经常被忽视。
对于第1点,优点在于松耦合,可测试性很好。如果在Controller里面想要使用某些Service,要么new出来,要么用单例的形式,如UserService.Instance,这样想对Controller写单元测试都不容易,它和这些Service耦合太紧密,无法将这些Service替换成Stub实现。因此,松耦合是必须的。要实现这个功能,必须让依赖注入框架来创建Controller,才有可能注入依赖并组装对象。MVC里面有一个ControllerFactory的东西,可以使用来达到这个目的。
a. 写一个类,继承自DefaultControllerFactory,例如 UnityControllerFactory : DefaultControllerFactory
b. 覆盖方法GetControllerInstance,使用依赖注入框架来创建Conroller
c. 修改Global.asax.cs, 在application_Start内注册使用自己的ControllerFactory,
ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory())
d. 对Controller进行构造函数注入,例如:
public class UserController : Controller
{
public UserController(IUserService, userService, IMessageService messageService)
…
}
从现在开始,所有的Controller都是通过依赖注入框架来创建的,新增的Service就在依赖注入框架里面注册,Controller要使用哪些Service就往构造函数里加,反正框架会注入进来。
第2点, 类如HttpContext.Current.session[“xxx”] = …, HttpContext.Current.Cache.Insert…此样的代码充斥在各个角落。有问题吗?还是老问题,可测试性,可替换性。
像HttpContext这种东西,几乎是不能Mock或者Stub的,只要代码中使用了HttpContext,可以说它就没法做单元测试。为什么很多人都会这么用呢,一个原因是图方便图简单,二是没有写单元测试。要用Session直接用就好了,封装一下再用多麻烦啊,这就是图简单。
解法很简单,对HttpContext进行封装,例如ISessionPRovider, ICacheProvider,然后通过依赖注入框架,注入到Controller中去,这样的结果是代码可测试性高,而且想改变Cache机制也很方便。
意识不够。什么意识?让代码松耦合的意识。使用静态方法,静态变量,直接new依赖的对象,这些都是松耦合的反例。我们写代码的时候要规避它们。即使我们不用TDD(极端一点来说,现在不写单元测试),脑子里也要清楚记得,面向对象的法则、松耦合的一些原则等等,然后反应到代码上去。
这一点,记得好像园子里以前有人提到过。
最后一点,View中不写条件逻辑。View中一旦加入条件判断,就会使得代码特别难以维护,难以理解。如果在aspx文件中,看到以下的代码:
<% if (条件1) { %>
<div>
…
<% if(某某条件) { %>
…
<% } %>
</div>
<%} else if (条件2) { %>
…
<% } else { %>
…
<% } %>
这样的View让人很怕去改,生怕哪里改错了而自己又不知道。因为它写的太混乱,逻辑和显示穿插在一起,如果再混着一些动态的html元素,那就真的只能谁写的谁来弄。
我们可以怎样做呢?如果是比较复杂的条件逻辑,就放到Controller里面去做,然后返回不同的View。这样View又很简单,这些逻辑又可以被测试。没有谁规定,一个Action只能对应一个View。跟Class的道理一样,Class职责过多,就得进行拆分。View的逻辑过于复杂也得进行拆分。
这么拆分以后,有可能会出现几个View有重复的部分。那就具体情况具体解决了,可以使用ViewHelper,也可以把重复的东西再独立出来,不同的View来复用。记住,View是代码的一部分,不要觉得涉及到Html的部分乱就乱点。View也是需要持续被重构的。
这一篇着重强调的是,漂亮的代码有良好的可测试性。
[]
赞助商链接