2010-06-30 127 views
31

每當我重寫一個基類的方法,除了我的這個方法的實現,我似乎有3個選擇。如何「正確」重寫基類方法?

1)調用base.Method(),然後提供我的實現。

2)提供我的實現,然後調用base.Method()

3)只需提供我的實現。

最近在使用庫時,我已經意識到由於沒有實現庫所期望的方法而引入的一些錯誤。我不確定圖書館是否有問題,或者我的理解有問題。

我將舉一個例子。

public class ViewManager { 
    public virtual void Customize(){ 
     PrepareBaseView(); 
    } 
} 

public class PostViewManager { 
    public override void Customize(){ 
     base.Customize(); 
     PreparePostView(); 
    } 
} 


public class PreViewManager { 
    public override void Customize(){ 
     PreparePreView(); 
     base.Customize(); 
    } 
} 


public class CustomViewManager { 
    public override void Customize(){ 
     PrepareCustomView(); 
    } 
} 

我的問題在這裏怎麼可能一個子類知道(不考慮看看基類實現)的順序(或期權)是由父類的預期? 有沒有一種方法可以讓父類強制三個交替之一到所有的派生類?

+1

'PostViewManager','PreViewManager','CustomViewManager'繼承自'ViewManager'?如果是這樣,你應該編輯代碼。 – LaTeX 2011-02-16 05:53:42

回答

36

子類如何知道(無需查看基類實現)父類預期的順序(或選項)?

當你繼承和重寫方法時,沒有辦法「知道」這個。正確的文檔是這裏唯一的選擇。

有沒有一種方法,其中父類可以強制三個交替之一到所有的派生類?

這裏唯一的選擇是避免這個問題。而不是讓子類覆蓋的方法,它可以聲明非虛,並呼籲在適當的地方虛方法。例如,如果要強制執行的子類「先打電話給你的版本」,你可以這樣做:

public class BaseClass { 
    public void Method() // Non-virtual 
    { 
      // Do required work 

      // Call virtual method now... 
      this.OnMethod(); 
    } 

    protected virtual void OnMethod() 
    { // Do nothing 
    } 
} 

子類就可以「覆蓋」 OnMethod,並提供售後服務「方法」的工作出現這種情況的功能。

這是必需的原因是虛擬方法的設計允許子類完全替代父類的實現。這是有目的地完成的。如果您想防止這種情況,最好使該方法非虛擬化。

+1

你打敗了我。這是脆弱的基類**問題。解決方法爲+1(您也擊敗了我:),**模板方法模式**。您甚至可以創建受保護的'OnMethod'抽象,以便派生類知道它們*具有*提供它們自己的實現,而且它們不必調用基本實現(假設它沒有意義實例化'Base')。 – shambulator 2010-06-30 20:18:12

+0

+1這可以幫助您避免開發人員的衝突。 – Marc 2010-06-30 20:23:18

+0

@shambulator - Override是可選的,所以它可能無法與'OnMethod'抽象相提並論。它仍然是一個不錯的選擇,雖然 – 2010-06-30 20:24:42

1

簡短的回答是否定的。你不能以孩子調用基本方法的順序執行,或者根本不調用它。

從技術上講,這些信息應該包含在基礎對象的文檔中。如果您絕對必須在子類的代碼之前或之後運行一些代碼,則可以執行以下操作:

1)在基類中創建一個非虛函數。我們稱之爲MyFunction

2)在基類中創建一個受保護的虛函數。我們稱之爲_MyFunction

3)派生類擴展了_MyFunction方法。

4)讓MyFunction調用_MyFunction並在調用它之前或之後運行它需要運行的代碼。

這種方法是醜陋的,將需要大量的額外的代碼,所以我建議只是把通知的文件中。

+0

我不知道像PostSharp這樣的東西是否可以強制執行該命令。 – FrustratedWithFormsDesigner 2010-06-30 20:14:48

0

基本類的需求應該由庫設計者記錄。 這個問題就是爲什麼一些庫包含主要密封類的原因。

2

這就是爲什麼我覺得虛擬方法是危險的,當你把它們放在圖書館。事實是,如果不查看基類,你永遠不會知道,有時你必須啓動反射器,閱讀文檔或通過反覆試驗來處理它。

在編寫代碼時我自己,我一直累到遵循說規則:

重寫受保護的虛方法

派生類不需要調用基類的實現。即使未調用其實現,基類也必須繼續正常工作。

這取自http://msdn.microsoft.com/en-us/library/ms229011.aspx,但是這是用於事件設計,但我相信我在框架設計指南書(http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321246756)中閱讀了此內容。

但是,這顯然是不正確的,例如,ASP.NET Web窗體需要在Page_Load上進行基址調用。

所以,總之,它會變化,不幸的是沒有即時的知道方式。如果我有疑問,我會最初省略電話。

+0

多麼美妙的答案。我的確切想法。上投票。 – Xtro 2017-11-25 23:32:24