如何寫出漂亮的代碼——巧妙的接口擴展


最近對面向對象有了個新的領悟,特在此分享給大家。如果這個思想不對或者已經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,其實可以應用於任何地方。

思想的升華:

本人覺得使用“接口擴展”的設計要比用基類的設計要好些,因為“接口擴展”像是一種注入式的代碼,我們可以將接口封裝的特性注入到任何一個類上面,而不用去處理復雜的類的繼承。

給你的實體類注入新特性吧!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM