ASP.NET Routing介紹
您覺得ASP.NET Routing中最令人摸不著頭腦的設(shè)計(jì)是什么?我認(rèn)為是RouteBase類:
- public abstract class RouteBase
- {
- protected RouteBase() { }
- public abstract RouteData GetRouteData(HttpContextBase httpContext);
- public abstract VirtualPathData GetVirtualPath(
- RequestContext requestContext,
- RouteValueDictionary values);
- }
它為什么是一個沒有任何實(shí)現(xiàn)的抽象類,而不是一個接口(如下)?
- public interface IRoute
- {
- RouteData GetRouteData(HttpContextBase httpContext);
- VirtualPathData GetVirtualPath(
- RequestContext requestContext,
- RouteValueDictionary values);
- }
這樣做難道不更漂亮一些嗎?這樣代碼中都可以使用IRoute類型,避免RouteBase這種令人反感的命名出現(xiàn)(個人感覺,不知道有沒有同意的群眾)。退一步說,命名上的“美感”是小事……但是抽象類在.NET平臺中就產(chǎn)生了一個非常嚴(yán)重的限制:一個類無法繼承多個基類。因此,在.NET平臺上總是更傾向于使用接口,而不是抽象類。
但是接口里不可以有任何實(shí)現(xiàn),那么可復(fù)用的功能又放在哪里比較合適呢?《Framework Design Guildlines》告訴我們:在一個類庫中,***為接口定義一個默認(rèn)實(shí)現(xiàn),這樣也是開發(fā)人員進(jìn)行“擴(kuò)展”的一個“參考”。也就是說,如果真有什么需要復(fù)用的實(shí)現(xiàn),我們完全可以這么做:
- public abstract class RouteBase : IRoute
- {
- // reusable implementations
- }
- public class Route : RouteBase
- {
- // concrete implementations
- }
事實(shí)上,.NET平臺上有許多類庫也遵循了這個做法。一個典型的做法便是ASP.NET AJAX框架的Extender模型:
- public interface IExtenderControl {
- }
- public abstract class ExtenderControl : Control, IExtenderControl {
- }
甚至在ASP.NET AJAX Control Tookit項(xiàng)目中,還有更進(jìn)一步的擴(kuò)展:
- public abstract class ExtenderControlBase : ExtenderControl {
- }
- public class AnimationExtenderControlBase : ExtenderControlBase {
- }
- public class AutoCompleteExtender : AnimationExtenderControlBase {
- }
看來微軟在項(xiàng)目團(tuán)隊(duì)內(nèi)部推廣《Framework Design Guidelines》還不夠徹底。
在.NET平臺下,一個沒有任何實(shí)現(xiàn)的,純粹的抽象類可謂有百害而無一利。我很懷疑寫這段代碼的人剛從C++切換到C#——但是ASP.NET Routing中其實(shí)也有接口(如IRouteConstraint),為什么作者自己沒有意識到,也沒有人提出不同意見呢?微軟開發(fā)團(tuán)隊(duì)?wèi)?yīng)該有著嚴(yán)格的Code Review過程,怎么會讓這樣的代碼正式發(fā)布?要知道一個接口一旦公開,就不可以刪除了。也就是說,微軟很難彌補(bǔ)這個錯誤。
如果是方法名不好,或者職責(zé)有些不明確,這樣還可以在舊方法上添加ObsoleteAttribute(這樣編譯器便會提示用戶這個方法已經(jīng)過期),并且將舊方法的調(diào)用委托給新的實(shí)現(xiàn)。例如:
- public abstract class CodeDomProvider : Component
- {
- [Obsolete(
- "Callers should not use the ICodeCompiler interface and should
- instead use the methods directly on the CodeDomProvider class.
- Those inheriting from CodeDomProvider must still implement this
- interface, and should exclude this warning or also obsolete this
- method.")]
- public abstract ICodeCompiler CreateCompiler();
- [Obsolete(
- "Callers should not use the ICodeParser interface and should
- instead use the methods directly on the CodeDomProvider class.
- Those inheriting from CodeDomProvider must still implement this
- interface, and should exclude this warning or also obsolete this
- method.")]
- public virtual ICodeParser CreateParser();
- ...
- }
可是,現(xiàn)在的問題是一個“類”,而這個類已經(jīng)無處不在了,例如在RouteData中有一個屬性Route,它便是RouteBase類型——如果將其修改為IRoute接口,那么至少也需要項(xiàng)目重新編譯之后才能夠“升級”。而作為一個公開類庫,尤其是.NET這種成熟框架來說,應(yīng)該做到“無痛”才對。
這次微軟真搞笑了。以上介紹ASP.NET Routing。
原文出處博客園,作者趙劼
【編輯推薦】