<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      再談抽象類和接口

      2009-08-19 12:15  Jeffrey Zhao  閱讀(9556)  評論(69)    收藏  舉報

      昨天我質(zhì)疑了為什么定義RouteBase抽象類,而不是IRoute接口,我談到對于一個“沒有任何實(shí)現(xiàn)”的抽象類來說,開發(fā)人員應(yīng)該使用接口。不過在后面的評論中,有朋友給了我啟發(fā),讓我忽然想到更多的事情。晚上又再次翻了翻《Framework Design Guidelines》之后,打算再談一些東西,把這個問題討論地更加清楚一些。

      上次談了接口的好處,那么這次就主要談一下接口的缺點(diǎn)。

      API是會“升級”的。在一個類庫的新版本中,往往會對舊有的API進(jìn)行修改。作為一個公開的的API,應(yīng)該做到“無痛升級”,也就是說API的演變不應(yīng)該破壞現(xiàn)有的應(yīng)用。而類(class)相對于接口(interface)的優(yōu)勢之一,便是在于類適合進(jìn)行API的演變。

      試想,在類庫的1.0版本中定義了一個公開的接口,就比如IRoute吧,它其中有兩個成員。于是乎開發(fā)人員在使用1.0版本的時候,就會實(shí)現(xiàn)這個IRoute接口:

      public class MyRoute : IRoute
      {
          public RouteData GetRouteData(HttpContextBase httpContext) { ... }
      
          public VirtualPathData GetVirtualPath(
              RequestContext requestContext, RouteValueDictionary values) { ... }
      }
      

      于是到了2.0版本中,開發(fā)人員發(fā)現(xiàn),IRoute接口不夠用,需要加入新的成員——但是不行,因?yàn)镮Route在1.0中已經(jīng)公開了,這意味著如果向IRoute中添加新的成員,就可能會破壞外部已經(jīng)使用IRoute接口的實(shí)現(xiàn)(如上面的MyRoute)。因此,一旦公開接口發(fā)布之后,它就不能被修改了。進(jìn)而,這一點(diǎn)又可以引出了接口的一個設(shè)計準(zhǔn)則:接口的職責(zé)應(yīng)該尤其單一。例如.NET框架中的IComparable,IEnumerable等接口。因?yàn)槿绻O(shè)計了一個接口,其中包含了許多成員,那么在新版本中這個接口則更有可能需要補(bǔ)充新的功能……但是接口又不可以修改,這該怎么辦呢?

      的確是進(jìn)退兩難的情況。在《Framework Design Guildlines》里提出了一些沒辦法時的辦法,但書中也不得坦誠道,這些做法都不是好辦法。事實(shí)上真沒有什么好辦法。

      如果是“類”的話,問題就相對好辦多了,因?yàn)槲覀兛梢韵蝾愔刑砑有碌某蓡T——只要這個新成員不是abstract的,就不會破壞外部已經(jīng)出現(xiàn)的依賴。不過加上之后,API設(shè)計是否合理,語義是否清晰,就是另一回事情了。API設(shè)計不僅僅是技術(shù)活,每個舉動都是需要推敲的。因?yàn)橐坏┌l(fā)布,就沒法刪除了。

      因此在這里再次感謝那位匿名朋友在評論中的提醒,他指出RouteBase可能是為了“預(yù)留”而實(shí)現(xiàn)成抽象類的。

      說起語義和協(xié)議,可能就會涉及到接口的另一個特點(diǎn),或者說也是個“缺陷”,那就是協(xié)議并不明確。接口定義了成員,也就是限制了實(shí)現(xiàn)這個接口的“外觀”,但是對于“內(nèi)在”是做不了任何限制的。例如,我們可以讓一個方法拋出NotImplementedException,這便是“外強(qiáng)中干”的典型。還有一種情況,就比如IList<T>接口:

      public interface IList<T>
      {
          void Add(T item);
          int Count { get; }
      
          ...
      }
      

      IList<T>接口只是限制了接口的外部表現(xiàn):一個接受T類型的Add方法,還有表示元素數(shù)量的Count。但是在協(xié)議層面上,我們是無法限制這兩個成員的關(guān)系的。例如,Add方法調(diào)用過后,Count肯定會增加1嗎?此外還有,Add方法是不是線程安全的?僅通過接口都是不得而知的。

      如果是抽象類,我們可以實(shí)現(xiàn)的東西就多了。例如,我們可以實(shí)現(xiàn)這樣的一個抽象類:

      public abstract class ThreadSafeListBase<T>
      {
          private ReaderWriterLockSlim m_rwLock = new ReaderWriterLockSlim();
      
          public int Count { get; private set; }
      
          public void Add(T item)
          {
              this.m_rwLock.EnterWriteLock();
              try
              {
                  this.Count++;
                  this.AddCore(item);
              }
              finally
              {
                  this.m_rwLock.ExitWriteLock();
              }
          }
      
          protected abstract void AddCore(T item);
      
          ...
      }
      

      這么做,就在一定程度上對實(shí)現(xiàn)內(nèi)容進(jìn)行了約束。但是很明顯約束是不可能徹底的(如AddCore也可能拋出NotImplementedException),最徹底的約束便是一個sealed class——但這個很明顯,就已經(jīng)不是抽象了。

      接口的確有優(yōu)勢(可以讓類來實(shí)現(xiàn)多個接口,且struct實(shí)現(xiàn)接口不能繼承一個類),但是在這篇文章中我們也看到接口也是有一定缺陷的。設(shè)計需要平衡,沒有什么東西是最好的,也沒有什么東西總是最合適的。

      不過比較奇怪的是,有(不止一個)朋友回復(fù)說,使用抽象類是為了使用擴(kuò)展方法。我從來沒有看到過某個資料說接口和擴(kuò)展方法有任何沖突,事實(shí)上我們也可以為接口定義擴(kuò)展方法。由于一個類可以實(shí)現(xiàn)多個接口,而接口又可以實(shí)現(xiàn)擴(kuò)展方法,這似乎也又有了“多繼承”的意味。

      主站蜘蛛池模板: 国产精品中文字幕免费| 国产精品一区在线蜜臀| 国产嫩草精品网亚洲av| 悠悠人体艺术视频在线播放| 人人妻人人澡人人爽欧美一区双| 在线播放亚洲成人av| 精品国产午夜福利在线观看| 国产精品第一页中文字幕| 伊人久久大香线蕉av色婷婷色| 国产明星精品无码AV换脸| 任我爽精品视频在线播放| 亚洲欧美自偷自拍视频图片| 日日摸天天爽天天爽视频| 国产av丝袜熟女一二三| 国产熟女真实乱精品51| 午夜AAAAA级岛国福利在线| 亚洲中文字幕一区二区| 国产午夜精品一区二区三| 国产成人一区二区三区在线| 在线观看潮喷失禁大喷水无码| 变态另类视频一区二区三区 | 狠狠色噜噜狠狠狠狠777米奇| 99国产精品永久免费视频| 偷柏自拍亚洲综合在线| 安塞县| 四虎成人高清永久免费看| 亚洲一区二区三区在线观看精品中文| 国产精品天天看天天狠| 久久综合色最新久久综合色| 日本夜爽爽一区二区三区| 日本视频高清一区二区三区| 国产不卡一区二区在线视频| 成人乱码一区二区三区四区| 连山| 性姿势真人免费视频放| 高清破外女出血AV毛片| 石台县| 欧美精品一产区二产区| 加勒比精品一区二区三区| 2021国产精品视频网站| 国产精品熟女乱色一区二区|