如何写出漂亮的代码——巧妙的接口扩展

最近对面向对象有了个新的领悟,特在此分享给大家。如果这个思想不对或者已经out了,还请不要笑话。

本文的示例代码将以ASP.NET MVC为基础的,如果你没有MVC的基础,也不会影响阅读,因为本文探讨的核心是面向对象中的一个设计思想。

下面我先以一个简单的例子来描述它。

案例:

有时我们的一个项目包含多个网站,比如有一个管理员用的站点,有一个公司客户使用的站点,这2个站点会部署到不同的服务器。这2个站点都有一个注销登录的action。你可能首先想到,用一个UserControllerBase类来封装这个logout action,以实现代码的重用。这当然是我们首先考虑到的。但是,有时候这2个站点的controllers分别继承了不同的controllerBase,比如AdminControllerBase和ClientControllerBase,这时再用类的继承来实现就不太优雅了。

解决方案:

定义一个ILogoutController接口,然后对该接口写扩展方法Logout,然后再让不同站点的UserController实现这个接口。

代码:接口定义和扩展实现

namespace Demo
{
    public interface ILogoutController
    {

    }

    public static class LogoutControllerExtensions
    {
        public static ActionResult Logout<TController>(this TController controller)
            where TController : DemoControllerBase, ILogoutController
        {
            var service = IoC.GetService<IUserService>();
            service.Signout(controller.User.Identity.Name);
            controller.Session.Clear();
            controller.Session.Abandon();
            FormsAuthentication.SignOut();
            return controller.DemoRedirect("/login");
        }
    }
}

代码:让相应的controller实现该接口

namespace Demo.Admins
{
    public class UserController : AdminControllerBase, ILogoutController
    {
        public ActionResult Logoff()
        {
            return this.Logout();
        }
    }
}

namespace Demo.Clients
{
    public class UserController : ClientControllerBase, ILogoutController
    {
        public ActionResult Logoff()
        {
            return this.Logout();
        }
    }
}

上面代码的核心在于接口扩展方法的泛型约束 where TController : DemoControllerBase, ILogoutController。另外还请注意到扩展方法的最后一行代码:

return controller.DemoRedirect("/login");

由于System.Web.Mvc.Controller的Redirect方法是protected,为了让该方法公开出来,在这个例子中我们新加了一个DemoControllerBase,如下:

public class DemoControllerBase : Controller
{
    public RedirectResult DemoRedirect(string url)
    {
        return base.Redirect(url);
    }
}

public class AdminControllerBase : DemoControllerBase
{

}

public class ClientControllerBase : DemoControllerBase
{

}

其他适用场景:

可以说这一设计思想可以应用到任何场景,可以说这一思想即是面向对象编程思想的一部分。你可以发现,上面的代码是完全符合面向对象思想的。代码非常容易阅读,可维护性高,可扩展性强。

在我们的项目中,除了上面的ILogoutController外,还有一个IAddressEditorController。由于我们的项目分为4个站点,有很多的用户角色,地址编辑出现在很多地方。自从有了这个接口之后,代码就漂亮多了,如果客户想要增加一个地址编辑页面,对我们的成本的增加那就几乎是0.

“接口扩展”这一思想不仅仅是可以应用于web层的controller,其实可以应用于任何地方。

思想的升华:

本人觉得使用“接口扩展”的设计要比用基类的设计要好些,因为“接口扩展”像是一种注入式的代码,我们可以将接口封装的特性注入到任何一个类上面,而不用去处理复杂的类的继承。

给你的实体类注入新特性吧!

posted @ 2013-05-09 23:00  Leo C.W  Views(2049)  Comments(8Edit  收藏  举报