偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

有關(guān)virtual,override與擴(kuò)展點(diǎn)的討論

開(kāi)發(fā) 后端
所有的成員都應(yīng)該是virtual的嗎?這是一個(gè)由來(lái)已久的討論。本文對(duì)有關(guān)virtual,override與擴(kuò)展點(diǎn)的討論闡述了一番自己的見(jiàn)解。

Virtual即虛擬。在C#中,Virtual指的是虛方法或虛函數(shù)。有關(guān)這個(gè)Virtual有一個(gè)經(jīng)常被討論的問(wèn)題:所有的成員都應(yīng)該是virtual的嗎?

這是一個(gè)由來(lái)已久的討論,由于Java默認(rèn)所有的方法都是可以被override的(除非手動(dòng)寫(xiě)成final),因此從C#語(yǔ)言設(shè)計(jì)起初就有此番爭(zhēng)論,甚至讓Anders都出來(lái)解釋了一下。最近又有人在討論這方面話(huà)題了,雖然我的看法并沒(méi)有超出這些人所涉及的范疇,但是我還是打算談一下我的理解。退幾步說(shuō),就當(dāng)補(bǔ)充一些“實(shí)例”吧。

Virtual,Override與擴(kuò)展點(diǎn)的關(guān)系簡(jiǎn)述

此次的話(huà)題是由Ward Bell引起的,他在review了Roy Osherove的新書(shū)《The Art of Unit Testing》之后認(rèn)為,他不同意Roy給出的建議“將所有的成員默認(rèn)為virtual”,為此他還獨(dú)立開(kāi)篇解釋了他的觀(guān)點(diǎn)。這篇文章引起的討論較為熱烈,我也打算在詳細(xì)總結(jié)一番。與Ward觀(guān)點(diǎn)對(duì)應(yīng)的是,著名的Jeremy Miller希望.NET中所有的成員默認(rèn)就是virtual的,而“月寫(xiě)博客80篇”的Oren Eini甚至認(rèn)為所有的成員都應(yīng)該標(biāo)為virtual。

繼承一個(gè)類(lèi)并override掉其中的成員,是面向?qū)ο缶幊讨凶畛S玫姆绞街?。這是一種擴(kuò)展方式,而能夠被override的方法便是“擴(kuò)展點(diǎn)”。所以我認(rèn)為,是否把成員標(biāo)記為virtual,其實(shí)涉及到的概念便是“是否把它開(kāi)放為一個(gè)擴(kuò)展點(diǎn)”。Oren認(rèn)為“所有成員都應(yīng)該virtual”則意味著“任何成員都是可擴(kuò)展點(diǎn)”,而對(duì)于“默認(rèn)為virtual”的觀(guān)點(diǎn)來(lái)說(shuō),則意味著“傾向于打開(kāi)更多的擴(kuò)展點(diǎn)”——其實(shí)除了Oren有些極端外,“傾向性”代表的更多是一種“口味”,因?yàn)闊o(wú)論是Java還是.NET,都可以標(biāo)記一個(gè)成員能否被override。

從Virtual,Override與擴(kuò)展點(diǎn)延伸談去

我不想討論“口味”問(wèn)題,不過(guò)我的觀(guān)點(diǎn)與Ward類(lèi)似,即使在C#出現(xiàn)之前,我也一直不太喜歡Java的這個(gè)特性(不過(guò)當(dāng)時(shí)相關(guān)體會(huì)比較少,所以感覺(jué)并不強(qiáng)烈)。Oren認(rèn)為打開(kāi)更多擴(kuò)展點(diǎn),有助于從各方面進(jìn)行擴(kuò)展,他說(shuō)他的這個(gè)做法也過(guò)于也得到了較多的“實(shí)惠”。不過(guò)我認(rèn)為,這是由于Oren的能力過(guò)于厲害,并且知道該做什么不該做什么,并且可以對(duì)自己作的事情所負(fù)責(zé)決定的。

對(duì)于一個(gè)可“全面擴(kuò)展”的類(lèi)型來(lái)說(shuō),意味著開(kāi)發(fā)人員有更多的自由,進(jìn)而意味著選擇(即使是做同一件事情)。但是選擇多,則同樣意味著我們需要了解的多,一個(gè)不慎可能就會(huì)發(fā)現(xiàn)沒(méi)有得到預(yù)期的效果。例如,在繼承了ASP.NET的Control類(lèi)之后,您要改變它輸出的內(nèi)容,您會(huì)選擇覆蓋哪一個(gè)方法?

  1. protected internal virtual void Render(HtmlTextWriter writer)  
  2. {  
  3.     this.RenderChildren(writer);  
  4. }  
  5.  
  6. protected internal virtual void RenderChildren(HtmlTextWriter writer)  
  7. {  
  8.     ...  
  9. }  

您可能會(huì)說(shuō),覆蓋哪個(gè)都可以。但是,它們其實(shí)都有不同的語(yǔ)義,只是因?yàn)樵贑ontrol基類(lèi)中Render自身就是Render所有的子控件。但是到了子類(lèi)中,Render自身可能就會(huì)涉及到邊框等其他內(nèi)容了。如果您隨便選一個(gè),您的類(lèi)型看上去沒(méi)有問(wèn)題,但是如果別人希望繼承你寫(xiě)的類(lèi),補(bǔ)充一些實(shí)現(xiàn),那么你的“選擇”就會(huì)影響到他的結(jié)果了。當(dāng)然我并不是說(shuō)Control類(lèi)設(shè)計(jì)的不對(duì),它的設(shè)計(jì)我覺(jué)得是正確的,我只是想說(shuō)明,如果每個(gè)成員都可擴(kuò)展,那么用戶(hù)在真正需要擴(kuò)展的時(shí)候就會(huì)比較麻煩了。

架構(gòu)是一種擴(kuò)展,也是一種約束,限制了別人可以怎么做,也必須怎么做。我們雖然無(wú)法避免別人的惡意行為,但是良好的擴(kuò)展點(diǎn)也可以給別人更好的指導(dǎo)。

再舉一個(gè)例子。在.NET中,最容易擴(kuò)展的抽象元素是什么呢?應(yīng)該是“接口”。接口中的所有成員都是由實(shí)現(xiàn)方提供的,除了成員的簽名之外,接口并沒(méi)有作任何限制。正如我在之前寫(xiě)過(guò)的一篇文章里提到,別人完全可以實(shí)現(xiàn)出外強(qiáng)中干的對(duì)象:

  1. public interface IList<T>  
  2. {  
  3.     void Add(T item);  
  4.     int Count { get; }  
  5.    
  6.     ...  

根據(jù)接口中隱含的協(xié)議,Add方法調(diào)用之后,Count必須加一。但是這個(gè)協(xié)議并無(wú)法加諸于實(shí)現(xiàn)之上。如果要提供這方面的約束,我們只能公開(kāi)一部分的擴(kuò)展點(diǎn),而不是把所有的職責(zé)交給實(shí)現(xiàn)方:

  1. public abstract class ListBase<T>  
  2. {   
  3.     public int Count { getprivate set; }  
  4.    
  5.     public void Add(T item)  
  6.     {  
  7.         this.Count++;  
  8.         this.AddCore(item);  
  9.     }  
  10.    
  11.     protected abstract void AddCore(T item);  
  12.    
  13.     ...  

Ward也舉了一個(gè)“電梯”的例子。電梯有一個(gè)Up方法,調(diào)用它則意味著電梯上升。但是如果把Up這個(gè)關(guān)鍵行為擴(kuò)展出去,那么別人在“修改電路”(即override這個(gè)Up方法)的時(shí)候,可能就會(huì)把電梯搞亂套了,例如原本應(yīng)該先關(guān)門(mén)再啟動(dòng),現(xiàn)在可能先啟動(dòng)再關(guān)門(mén),甚至一旦Up電梯就下降了。Oren認(rèn)為擴(kuò)展方應(yīng)該為自己的擴(kuò)展負(fù)責(zé),但是我還是認(rèn)為,擴(kuò)展點(diǎn)應(yīng)該和成員訪(fǎng)問(wèn)級(jí)別等東西一樣,只給出必要的,控制住關(guān)鍵的。

最后的例子也是常見(jiàn)的:

  1. public class SomeClass  
  2. {  
  3.     public void SomeMethed()  
  4.     {  
  5.         this.SomeMethed(String.Empty);  
  6.     }  
  7.  
  8.     public void SomeMethed(string s)  
  9.     {  
  10.         this.SomeMethod(s, 0);  
  11.     }  
  12.  
  13.     public virtual void SomeMethod(string s, int i)  
  14.     {  
  15.         // ...  
  16.     }  
  17. }  

為了方便起見(jiàn),我們常常會(huì)對(duì)類(lèi)型中的方法給出重載,其中大部分的重載最終都委托給一個(gè)唯一的核心方法。當(dāng)用戶(hù)繼承SomeClass類(lèi)之后,他便擁有了一個(gè)唯一的擴(kuò)展點(diǎn),這樣便可以確保這個(gè)類(lèi)的行為按照一定的“準(zhǔn)則”在正常開(kāi)展。否則的話(huà),用戶(hù)就需要在三個(gè)方法中進(jìn)行選擇性的override,并且要平衡三者的行為。因?yàn)樵跀U(kuò)展SomeClass的時(shí)候,并不知道SomeClass的使用者會(huì)調(diào)用SomeMethod的哪個(gè)重載。

這對(duì)于單元測(cè)試一樣。如果三個(gè)方法都可以Mock,那么在測(cè)試時(shí)我們可能就會(huì)去“猜測(cè)”用戶(hù)究竟調(diào)用了哪個(gè)SomeMethod重載,而這是不確定的,也是容易變化的。如果我們只有一個(gè)重載可以Mock,那么則意味著“別挑了,就是這個(gè)”。所以,我有時(shí)候也不太喜歡Type Mock如此強(qiáng)大有力的Mock框架,因?yàn)樗赡軙?huì)破壞了被測(cè)試方的設(shè)計(jì),把一切都變成了擴(kuò)展點(diǎn)——雖然這對(duì)于測(cè)試來(lái)說(shuō)的確很方便,幾乎不輸給動(dòng)態(tài)語(yǔ)言了。

“可測(cè)試性”也是設(shè)計(jì)出來(lái),不是語(yǔ)言或平臺(tái)自動(dòng)賦予的。這就是“design for testability”的體現(xiàn)之一吧。

以上就是有關(guān)virtual,override與擴(kuò)展點(diǎn)的一些討論。本文來(lái)自老趙點(diǎn)滴:《所有的成員都應(yīng)該是virtual的嗎?》

【編輯推薦】

  1. C#反射命名空間淺析
  2. C#靜態(tài)方法概念解析實(shí)例
  3. C#靜態(tài)方法與非靜態(tài)方法的比較
  4. C#靜態(tài)方法應(yīng)用實(shí)例詳解
  5. C#反射概念以及實(shí)例詳解
責(zé)任編輯:yangsai 來(lái)源: 老趙點(diǎn)滴
相關(guān)推薦

2010-08-04 14:33:42

自動(dòng)掛載nfs

2015-05-28 11:17:37

溫哥華峰會(huì)OpenStackDocker

2010-03-02 09:14:00

Linux創(chuàng)建用戶(hù)命令

2009-08-12 17:33:25

繼承與擴(kuò)展方法

2009-09-14 19:44:27

LINQ To SQL

2009-08-04 16:06:19

ASP.NET代碼分離

2009-07-06 13:23:12

C#面向集合

2009-08-28 15:28:22

C# overridenew隱藏

2009-08-13 18:00:48

Eclipse重構(gòu)功能擴(kuò)展點(diǎn)

2024-05-14 10:03:51

2012-02-13 09:30:51

響應(yīng)式Web設(shè)計(jì)

2023-11-28 08:01:25

2023-12-01 07:28:40

SpringbootBean

2023-09-28 08:49:41

springBean

2010-05-05 14:01:51

Unix系統(tǒng)

2011-06-16 14:46:21

2009-12-25 17:11:40

ADO方法

2019-11-22 16:05:44

阿里巴巴技術(shù)開(kāi)源

2021-03-02 10:32:17

合規(guī)性控制風(fēng)險(xiǎn)管理領(lǐng)導(dǎo)者

2009-08-19 15:50:52

松散耦合
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)