2017-07-14 164 views
1
namespace NUnitTestAbstract 
{ 
    public abstract class BaseTestClass1 
    { 
     public abstract void BaseTestClass1Method(); 
    } 

    public abstract class BaseTestClass2 : BaseTestClass1 
    { 
     // not overriding BaseTestClass1Method, child classes should do 
     public void SomeTestMethodA() { } 

     public void SomeTestMethodB() { } 
    } 

    public abstract class BaseTestClass3 : BaseTestClass1 
    { 
     // not overriding BaseTestClass1Method, child classes should do 
     public void SomeTestMethodX() { } 

     public void SomeTestMethodY() { } 
    } 

    public class TestClass2A : BaseTestClass2 
    { 
     public override void BaseTestClass1Method() 
     { 
      // do stuff 
     } 
    } 

    public class TestClass2B : BaseTestClass2 
    { 
     public override void BaseTestClass1Method() 
     { 
      // do same stuff as TestClassA 
     } 
    } 


    public class TestClass3A : BaseTestClass3 
    { 
     public override void BaseTestClass1Method() 
     { 
      // do stuff 
     } 
    } 

    public class TestClass3B : BaseTestClass3 
    { 
     public override void BaseTestClass1Method() 
     { 
      // do same stuff as TestClass3A 
     } 
    } 
} 

在這一刻我有上述建設。擴展另一個基類的基類。基類由兩個子類擴展。 BaseTestClass1Method的實現對於兩個子類是相同的。如果可以從兩個父母延伸,我會創建一個延伸BaseTestClass1的類,實現BaseTestClass1Method。然後這兩個子類將擴展BaseTestClass2和新類,以便我只需要實現BaseTestClass1Method一次 當我添加另一個BaseTestClass3(與BaseTestClass2相同級別)從BaseTestClass1擴展並從中創建子類時,我有更多的重複代碼實施BasetestClass1Method。 如何用正確的模式解決這個問題?c#繼承多個父母

以下是一個實現的例子:

namespace NUnitTestAbstract 
{ 
    public interface IServer { } 

    public abstract class ServerBase 
    { 
     public abstract IServer GetServerInstance(); 
    } 

    public abstract class SomeTests1Base : ServerBase 
    { 
     // not overriding BaseTestClass1Method, child classes should do 
     public void SomeTestMethodA() { } 

     public void SomeTestMethodB() { } 
    } 

    public abstract class SomeTests2Base : ServerBase 
    { 
     // not overriding BaseTestClass1Method, child classes should do 
     public void SomeTestMethodX() { } 

     public void SomeTestMethodY() { } 
    } 

    public class TestClass2A : SomeTests1Base 
    { 
     public override IServer GetServerInstance() 
     { 
      IServer serverX = null; 
      return serverX; 
     } 
    } 

    public class TestClass2B : SomeTests1Base 
    { 
     public override IServer GetServerInstance() 
     { 
      IServer serverX = null; 
      return serverX; 
     } 
    } 


    public class TestClass3A : SomeTests2Base 
    { 
     public override IServer GetServerInstance() 
     { 
      IServer serverY = null; 
      return serverY; 
     } 
    } 

    public class TestClass3B : SomeTests2Base 
    { 
     public override IServer GetServerInstance() 
     { 
      IServer serverY = null; 
      return serverY; 
     } 
    } 
} 
+0

如果BaseTestClass1Method真的是一樣的,那麼爲什麼不只是製作BaseTestClass1具體並在那裏實現該方法呢?您可以對子類中可能有所不同的任何屬性/方法進行保護性覆蓋。或者我錯過了什麼? – kpollock

回答

2

您可以在BaseTestClass2中實現BaseTestClass1Method,以便TestClassA和TestClassB都獲得相同的實現。然而,根據你的要求,走這條路可能會以地獄的繼承結束。

代替從BaseTestClass1繼承BaseTestClass2,您可以通過其構造函數(依賴注入(DI))將實現BaseTestClass1的實例傳遞到BaseTestClass2中。然後在TestClassA和TestClassB中簡單地調用注入實例的BaseTestClass1Method方法。這將您的繼承級別降低到1.

使用DI容器(如Autofac或Unity)將BaseTestClass1的正確實現注入到BaseTestClass2的後繼者中。

UPDATE

所以從你的榜樣工作

namespace NUnitTestAbstract 
{ 
    public interface IServer { } 

    public class BaseServer() 
    { 
     private IServer _server; 

     public BaseServer(IServer server) 
     { 
      _server = server; 
     } 

     public IServer GetServerInstance() 
     { 
      return _server; 
     } 
    } 

    public class SomeTests1 : ServerBase 
    { 
     // not overriding BaseTestClass1Method, child classes should do 
     public void SomeTestMethodA() { } 

     public void SomeTestMethodB() { } 
    } 

    public class SomeTests2 : ServerBase 
    { 
     // not overriding BaseTestClass1Method, child classes should do 
     public void SomeTestMethodX() { } 

     public void SomeTestMethodY() { } 
    } 
} 

public class ServerA : IServer 
{ 
    //Implementation 
} 

public class ServerB : IServer 
{ 
    //Implementation 
} 

VAR someTests1 =新SomeTests1(新服務器A()); var someTests2 = new SomeTests2(new ServerB());

請注意,我已經刪除了抽象類並將服務器實現注入到新實例中。

我已經放棄了TestClass(1..n),因爲我看不到他們的需要,但只有您可以知道答案。

另外我寫了這段代碼,因此它沒有經過測試,也沒有檢查過它是否編譯過,但你應該能夠得到它的要點。希望能幫助到你。

+0

謝謝,一個例子會很棒! –

+0

謝謝不,我可以嘗試一下我的真實實施 –

2

使用接口而不是抽象類。您可以從多個接口繼承,但只能從一個類繼承。

+0

我沒有找到與接口正確的解決方案。 BaseTestClass2實現了兩個測試方法,然後由兩個子類共享。 BaseTestClass1也應該有一個我可以與兩個子類共享的實現。 –

+0

然後你需要把所有的方法放在一個類中。認爲這是唯一的解決方案。 –

+0

我用一個擴展示例編輯了這個問題 –

6

從兩個類(或抽象類)派生不支持由於Diamond problem。調用父級方法時類型D的實例 - 它如何知道哪個父級?

enter image description here

,而不是與許多抽象類深繼承樹使用接口和組成。

  • 接口定義API
  • 成分通過具體實施。

你的邏輯是用一些接口來定義的,並且對於那個特定的邏輯有不同的具體類型。然後像TestClassb一個類可以創建所需邏輯的一個實例,或者更好的是依賴於它在它的構造:

public class Derived 
{ 
    public Derived(ILogic someDependentLogic) { } 
} 

在你的代碼中的註釋你說TestClass2B,它具有相同的行爲TestClassA但它取而代之的是從BaseTestClass2。你應該適當考慮你的繼承樹。應該TestClass2B是一種BaseTestClass2?或者它應該是一種TestClassA? 如果它實際上是一種「種」TestClassA,則改爲繼承它。

所有的答案都是特定領域的,但我建議你閱讀作文:它會幫助你理解你有什麼樣的關係,什麼是你的情況的正確設計。

  1. Composition vs. Inheritance
  2. Prefer composition over inheritance?
  3. Difference between Inheritance and Composition

而且有一些很好的設計模式來看待,如StateStrategryDecoratordofactory

看到的後發優勢Composition以及何時使用它你可以n看看SOLIDInversion Of Control它會幫助它們很好地融合在一起。

+0

我沒有找到接口的正確解決方案。 BaseTestClass2實現了兩個測試方法,然後由兩個子類共享。 BaseTestClass1也應該有一個我可以與兩個子類共享的實現。 –

+0

幾年前鑽石問題沒有解決嗎?我想鮑勃叔叔甚至談過這件事。 – FCin

+0

@WernerKellens - 看起來'TestClassb'更像是一個'TestClassA'的類型而不是基類,那麼也許你應該從'TestClassA'派生它。但是你仍然會想到的是深層的繼承樹,它使得代碼不那麼靈活 - 在哪裏使用組合有助於解決它 –

1

使用接口別人的建議:

namespace NUnitTestAbstract 
    { 
     public interface IBaseTes1 
     { 
      void BaseTestClass1Method(); 
     } 

     public abstract class BaseTestClass2 : IBaseTes1 
     { 
      void IBaseTes1.BaseTestClass1Method() 
      { 

      } 

      // not overriding BaseTestClass1Method, child classes should do 
      public void SomeTestMethodA() { } 

      public void SomeTestMethodB() { } 
     } 

     public class TestClassA : BaseTestClass2 
     { 
     } 

     public class TestClassb : BaseTestClass2 
     { 
     } 
    } 
+0

因此,如果「由他人建議」爲什麼發佈一個單獨的答案與相同的東西? –

+0

我編輯了一個擴展的例子的問題。問題是BaseTestClass2不應該實現BaseTestClass1Method。子類應該但子類實現相同 –

2

我不明白你爲什麼只是沒有在BaseTestClass2覆蓋BaseTestClass1Method

public abstract class BaseTestClass2 : BaseTestClass1 
    { 
     public override void BaseTestClass1Method() 
     { 
      // do same stuff as TestClassA 
     } 
    } 

爲了達到這樣的目的,你可以使用不同的模式,如

策略模式:http://www.dofactory.com/net/strategy-design-pattern

狀態模式:http://www.dofactory.com/net/state-design-pattern

+0

因爲子類之間的實現可能不同。我改變了我的例子。對於TestClass3A和TestClass3B,實現是不同的 –

+0

如果需要,仍然可以覆蓋子類中的方法。 –