2
   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
        }
    }
}

At this moment I have the above construction. A base class extending another base class. The base class is extended by two child classes. The implementation of BaseTestClass1Method is the same for the two child classes. If it was possible to extends from two parents I would create a class extending BaseTestClass1 implementing BaseTestClass1Method. The two child classes would then extend BaseTestClass2 and the new class so that I only have to implement BaseTestClass1Method once When I add another BaseTestClass3 (same level as BaseTestClass2) extending from BaseTestClass1 and create child classes from it, I have more duplicate code for the implementation of BasetestClass1Method. How can I solve this with the correct pattern?

Here's a more implemented example:

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;
        }
    }
}
Werner Kellens
  • 105
  • 1
  • 14
  • If BaseTestClass1Method really is the same, then why not just make BaseTestClass1 concrete and implement the method there? You can have protected overrides for any properties / methods that might be different in the child classes. Or what have I missed? – kpollock Jul 14 '17 at 07:45

5 Answers5

6

deriving from two classes (or abstract classes) is not supported due to the Diamond problem. An instance of type D when calling a parent method - how does it know of which parent?

enter image description here

Instead of deep inheritance trees with many abstract classes use interfaces and composition.

  • Interfaces to define the API
  • Composition to pass specific implementation.

Have your logic be defined with some interface and have the different concrete types for that specific logic. Then a class like TestClassb can create an instance of the desired logic or better still depend on it in its constructor:

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

In your code comments you say about TestClass2B that it has same behavior as TestClassA but it instead derives from BaseTestClass2. You should properly think about your inheritance tree. Should TestClass2B be a type of BaseTestClass2? Or should it be a type of TestClassA? If it is actually a "kind of" TestClassA then inherit it instead.

All together the answers are domain specific but I recommend you read about composition: It will help you understand what kind of relationships you have and what is the correct design for your situation.

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

Further there are some good Design Patterns to look at, such as State, Strategry, Decorator under dofactory

After seeing the advantages of Composition and when to use it you can have a look at SOLID and Inversion Of Control it will help it all fit nicely together.

Gilad Green
  • 36,708
  • 7
  • 61
  • 95
  • I don't find the correct solution with interfaces. BaseTestClass2 implements the two test methods which then are shared by the two child classes. BaseTestClass1 should also have a implementation that I can share with the two child classes. – Werner Kellens Jul 14 '17 at 07:26
  • Wasn't diamond problem solved years ago? I think Uncle Bob had even a talk about it. – FCin Jul 14 '17 at 07:26
  • @WernerKellens - it seems like `TestClassb` is more a type of `TestClassA` than of the base, then maybe you should have it derived from `TestClassA` instead. But still what you are coming to is deep inheritance trees which make the code less flexible - where using composition helps to solve it – Gilad Green Jul 14 '17 at 07:29
  • @WernerKellens - Did this answer help you solve your problem? – Gilad Green Jul 17 '17 at 15:54
  • @GiladGreen thanks. Yes it did, I learned a lot from your liniks. I learned how not to do it an togehter with the other answer I know how I should do it: by using interfaces and/or dependency injection. – Werner Kellens Jul 18 '17 at 05:46
  • 1
    @WernerKellens - Great to hear :) SOLID really makes life much simpler. – Gilad Green Jul 18 '17 at 05:47
2

Use interfaces instead of abstract classes. You can inherit from multiple interfaces, but only from one class.

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
  • I don't find the correct solution with interfaces. BaseTestClass2 implements the two test methods which then are shared by the two child classes. BaseTestClass1 should also have a implementation that I can share with the two child classes. – Werner Kellens Jul 14 '17 at 07:26
  • Then you need to put all methods in one class. Think it's the only solution. – Michał Turczyn Jul 14 '17 at 07:28
2

I didn't understand why are you just not overriding BaseTestClass1Method in BaseTestClass2

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

To achieve such goal you might use different patterns like

Strategy Pattern : http://www.dofactory.com/net/strategy-design-pattern

State Pattern : http://www.dofactory.com/net/state-design-pattern

Deniz Gokce
  • 71
  • 1
  • 6
2

you could implement BaseTestClass1Method in BaseTestClass2 so that both TestClassA and TestClassB get the same implementation. Depending on your requirements however, going this path might end in inheritance hell.

Instead of inheriting BaseTestClass2 from BaseTestClass1 you can pass an instance that implements BaseTestClass1 into BaseTestClass2 via its constructor (dependence injection (DI)). Then in TestClassA and TestClassB simply call the BaseTestClass1Method method of the injected in instance. This reduces your inheritance levels to just 1.

Use a DI container such as Autofac or Unity to inject the correct implentation of BaseTestClass1 into decendants of BaseTestClass2.

UPDATE

So working from your example

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 = new SomeTests1(new ServerA()); var someTests2 = new SomeTests2(new ServerB());

Note that I've removed the abstract classes and injected the server implementations into the new instances.

I've dropped the TestClass(1..n) because I cannot see a need for them but only you can know the answer to that.

Also I've written this code on the fly so it has not been tested nor have I checked if it even compiles but you should be able to get the gist of it. Hope it helps.

There is no spoon
  • 1,775
  • 2
  • 22
  • 53
1

Use the interface as suggested by others:

 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
        {
        }
    }
Yawar Murtaza
  • 3,655
  • 5
  • 34
  • 40
  • I edited the question with a extended example. The problem is that BaseTestClass2 shouldn't implement BaseTestClass1Method. The child classes should but the implementation is the same for the child classes – Werner Kellens Jul 14 '17 at 07:41