c#继承多个父母

时间:2017-07-14 07:18:24

标签: c# inheritance multiple-inheritance

   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一次 当我从BaseTestClass1添加另一个BaseTestClass3(与BaseTestClass2相同的级别)并从中创建子类时,我有更多的重复代码来实现BasetestClass1Method。 如何用正确的模式解决这个问题?

这是一个更实施的例子:

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

5 个答案:

答案 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
  4. 此外,还有一些好的设计模式可供查看,例如dofactory下的StateStrategryDecorator

    在看到Composition的优势以及何时使用它之后,您可以查看SOLIDInversion Of Control它将有助于它们完美地融合在一起。

答案 1 :(得分:2)

使用接口而不是抽象类。您可以从多个接口继承,但只能从一个类继承。

答案 2 :(得分: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

答案 3 :(得分:2)

您可以在BaseTestClass2中实现BaseTestClass1Method,以便TestClassA和TestClassB获得相同的实现。但是,根据您的要求,走这条路可能会以继承地狱结束。

您可以通过其构造函数(依赖注入(DI))将实现BaseTestClass1的实例传递到BaseTestClass2,而不是从BaseTestClass1继承BaseTestClass2。然后在TestClassA和TestClassB中简单地调用实例中注入的BaseTestClass1Method方法。这会将继承级别降低到1。

使用诸如Autofac或Unity之类的DI容器将BaseTestClass1的正确实现注入BaseTestClass2的后代。

<强>更新

从你的例子开始

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());

请注意,我已删除抽象类并将服务器实现注入新实例。

我放弃了TestClass(1..n),因为我看不出对它们的需求,但只有你能知道答案。

此外,我已经动态编写了这段代码,所以它还没有经过测试,也没有检查它是否可以编译,但你应该能够得到它的要点。希望它有所帮助。

答案 4 :(得分: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
        {
        }
    }