簡體   English   中英

有沒有更好的方法從其抽象基類調用派生類的重寫方法?

[英]Is there a better way to call a derived class's overridden method from its abstract base class?

我有一個抽象的基類,從中派生出許多類。 我希望派生類能夠覆蓋基類中定義的虛方法,但基類中有復雜的邏輯,用於確定在任何特定時刻是否“啟用”被覆蓋的方法。

考慮這個代碼 - 一種可能的解決方案 - 例如:

public abstract class AbstractBaseClass
{
  public bool IsMethodEnabled { get; set; }

  public virtual void DerivedMethod() { }

  public void Method()
  {
    if (IsMethodEnabled)
      DerivedMethod();
  }
}

public class DerivedClass : AbstractBaseClass
{
  public override void DerivedMethod()
  {
    Console.WriteLine("DerivedMethod() was called.");
  }
}

在上面的例子中, IsMethodEnabled是更復雜的邏輯的簡寫,它確定是否應該調用DerivedMethod - 它是我想要封裝在基類中的代碼,這樣我就不必在每個派生類中重現它。

設計按預期工作。 如果我運行此示例代碼:

AbstractBaseClass a1 = new DerivedClass() { IsMethodEnabled = false };
AbstractBaseClass a2 = new DerivedClass() { IsMethodEnabled = true };

a1.Method();
a2.Method();

......正如預期的DerivedMethod ,我看到了對DerivedMethod一次調用。

但有些事情讓我覺得這個實現錯了。 我覺得必須有更優雅的方式來處理這個問題。 有沒有更好的方法從其抽象基類中有選擇地調用派生類的方法實現? 有沒有一種設計模式可以更好地為我服務?

換句話說,上面的代碼“聞”了嗎?

這是一個非常合理的實現。

我建議的主要變化是:

  • 使實現protected功能的虛方法而不是公共方法
  • 為此使用更合適的命名。 也許更像是public void Method()protected virtual void OnMethod()

我同意里德認為這是一個合理的實施。

但是,我會考慮以下幾點:你想在這里保護誰? 我很樂意設計基類,以便它們可以輕松安全地擴展,但我也認為編寫派生類的開發人員比編寫基類的開發人員更了解 他們可能比你更了解給定的方法是否“啟用”。

它不像其他模板方法那樣“聞”,而某些人不喜歡這些模板方法 我傾向於同意這里提出的一些觀點。 特別是這兩個:

  • 很難理解程序流程 - 根據我的經驗,只需要很少的模板方法和繼承級別來調試或理解方法調用的順序很困難(少至2或3)。 當真正推送模板方法時(多個級別的許多抽象方法),調試這種系統會變得很痛苦。

  • 難以維護 - 保留了大量代碼,大量使用模板方法,這可能具有挑戰性。 這種系統很快就會變得脆弱。 任何一個級別的更改都可能會干擾模板方法中該級別之上或之下的操作。 在添加新功能時經常會出現不可預測的感覺,因為很難預測在所有情況下行為將如何變化。 您通常還會通過拆分模板類的算法部分並插入更多層來構建更精細和更精細的調整,從而加劇問題。

一般來說,我認為你必須非常小心使用模板方法,並保持簡單和專注。

看來你正試圖解決從方法本身調用方法的決定 如果擁有基類的唯一理由是封裝該決策,並使其代碼可重用,我認為您可以使用更松散耦合的設計,這將簡化單獨測試每個行為:

public interface IDoSomething {
  void Method();
}

public class ConditionallyDoSomething : IDoSomething {
  private IDoSomething _wrapped;

  public ConditionallyDoSomething(IDoSomething wrapped) {
    _wrapped = wrapped;
  }

  public bool IsMethodEnabled { get; set; } // could be quite complex...

  public void Method() {
    if (IsMethodEnabled) {
      _wrapped.Method();
    }
  }
}

public class DoSomething : IDoSomething {
  public void Method() {
    // do something...
  }
}

這樣,您可以模擬IDoSomething並分別測試每個部分(決策和功能)。 但是,如果你真的在這兩種行為中都有一些復雜的邏輯可以從這種分離中獲益,那么這是有道理的。 我只想嘗試替代其他優秀答案。 最終,這取決於您的具體情況。

您可以將所有需要覆蓋的方法標記為抽象,並將那些可以選擇覆蓋的方法標記為虛擬。 請參閱C#抽象類

這取決於IsMethodEnabled(實際)的價格是多少,假設它不是如圖所示的編譯器生成的,以及IsMethodEnabled是否會頻繁更改,以及是否有數百種方法具有那么少的“已啟用”邏輯位,以及Method()是否是真正的性能關鍵路徑。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM