如何在这里分解代码重复?

时间:2009-09-27 02:26:32

标签: c# design-patterns inheritance refactoring multiple-inheritance

所以,我想听听你们对此的看法。

我有一个项目,其中三个不同的继承路径需要全部实现另一个基类。这将是多重继承,在C#中是不允许的。我很好奇如何在没有代码重复的情况下实现这一点。

编辑:我不拥有这三个班级。这三个类来自第三方代码。所以我不能让它们都扩展我的基类。

现在我正在使用三个不同的类,每个类扩展一个不同的基类。然后我在三个抽象类中都有相同的代码。

我可以使用单个界面,但我仍然需要复制代码。

我可以创建一些实现代码的静态类,然后在3个抽象类的每一个中引用它。它会消除重复,但是,我不确定我对此的看法。我可以在接口上实现Extensions方法,但接口本身将是空的,扩展方法(包含重复的代码)将在一个完全不同的文件中,这似乎不太正确。另外,我无法在扩展方法中实现属性...

如何在此处分解代码重复?

编辑,继承树:

class Class1 : 3rdPartyBaseClass1 { }
class Class2 : 3rdPartyBaseClass2 { }
class Class3 : 3rdPartyBaseClass3 { }

我想要在上面的每个类中使用代码,但我无法将其添加到3rdPartyClasses。

5 个答案:

答案 0 :(得分:6)

创建Class1,Class2和Class3可以实现的接口。然后将您的代码放在扩展方法中,以便它适用于所有。

interface IMyInterface {
    void Foo();   //these are the methods that these 
        //classes actually have in common
    void Bar();    
}

public class Class1 : 3rdPartyBaseClass1, IMyInterface {
    // whatever

}

public static class IMyInterfaceExtensions {
    public static void CommonMethod(this IMyInterface obj) {
        obj.Foo();
        obj.Bar();
    }
}

public static class Program {
    public static void Main() {
        var instance = new Class1();
        instance.CommonMethod();
    }
}

答案 1 :(得分:5)

好的,你可以做一些类似于我之前的建议,也类似于递归的建议。对于所有三个派生类所需的功能,您可以创建一个单独的接口以及一个实现该接口的类(称为“实施者”,用于踢脚)(并且具有您希望在每次调用时执行的实际代码) )。

然后,在每个派生类中,实现Interface 创建Implementer的私有实例。在每个接口方法中,您只需将调用传递给Implementer的私有实例。由于Implementer和派生类都实现了您的接口,因此您对接口所做的任何更改都需要您相应地修改Implementer和派生类。

你的所有代码都在一个地方,除了所有的行都将调用传递给实现者的私有实例(显然多重继承会比这更好,但是你和你拥有的军队开战,而不是你希望你拥有的军队。)

更新:只是将类的公共实例添加到每个派生类中?

public class DerivedClass1 : ThirdPartyClass1
{
    public MyClass myClass = new MyClass();
}

或者如果您关心Demeter是谁并且您通过LOC获得报酬:

public class DerivedClass1 : ThirdPartyClass1
{
    private MyClass _myClass = new MyClass();
    public MyClass myClass
    {
        get
        {
            return _myClass;
        }
    }
}

然后你就像这样调用MyClass方法:

DerivedClass1 dc1 = new DerivedClass1();
dc1.myClass.DoSomething();

这样,我们都可以睡觉了。

答案 2 :(得分:4)

类似于MusiGenesis的建议,如果你需要第三方课程的功能,但 没有从他们那里下来,你可以使用组成如下:

class ThirdPartyBaseClass1
{
    public void DoOne() {}
}

class ThirdPartyBaseClass2
{
    public void DoTwo() { }
}

class ThirdPartyBaseClass3
{
    public void DoThree() { }
}

abstract class Base
{
    public void DoAll() { }
}

class Class1 : Base
{
    public void DoOne() { _doer.DoOne(); }
    private readonly ThirdPartyBaseClass1 _doer = new ThirdPartyBaseClass1();
}

class Class2 : Base
{
    public void DoTwo() { _doer.DoTwo(); }
    private readonly ThirdPartyBaseClass2 _doer = new ThirdPartyBaseClass2();
}

class Class3 : Base
{
    public void DoThree() { _doer.DoThree(); }
    private readonly ThirdPartyBaseClass3 _doer = new ThirdPartyBaseClass3();
}

这也使您可以自由定义所需的任何接口并在类上实现它们。

答案 3 :(得分:1)

听起来你需要将新的抽象类插入到继承树中,无论这三条路径聚集在一起,但实际上还没有足够的信息可以告诉你。如果您可以发布一些继承树,那将会有很大帮助。

答案 4 :(得分:1)

我认为您可能希望使用合成而不是继承。究竟如何做到这一点取决于第三方类的外观,以及您自己的代码是什么样的。与您的问题相关的一些更具体的代码会有所帮助,但是,例如,假设您希望拥有三个不同的第三方GUI小部件,这些小部件都需要使用您自己的初始化代码进行自定义。

案例1 :假设您的第三方小部件如下:

public interface IThirdPartyWidget {
  public void doWidgetStuff();
}

public class ThirdPartyWidget1: ThirdyPartyWidget implements IThirdPartyWidget {
 ...
}

public class ThirdPartyWidget2: ThirdPartyWidget implements IThirdPartyWidget {
 ...
}

你可以这样做:

public class MyWidget implements IThirdPartyWidget {
 private IThirdPartyWidget delegateWidget;
 public MyWidget(IThirdPartyWidget delegateWidget) {
  this.delegateWidget = delegateWidget;
 }

 public void doWidgetStuff() {
  delegateWidget.doWidgetStuff();
 }
}

案例2:假设您绝对需要扩展这些小部件,并且必须重构自己的代码:

public class MyWidget1: ThirdPartyWidget1 {
 public void myMethod() {
  runMyCode();
 }

 private void runMyCode() {
  //something complicated happens
 }
}

public class MyWidget2: ThirdPartyWidget2 {
 public void myMethod() {
  runMyCode();
 }

 private void runMyCode() {
  //something complicated happens
 }
}

这可以成为:

public class MyCodeRunner {
 public void runMyCode() {
  //...
 }
}

public class MyWidget1: ThirdPartyWidget1 {
 private MyCodeRunner myCode = new MyCodeRunner();
 public void myMethod() {
  myCode .runMyCode();
 }
}

public class MyWidget2: ThirdPartyWidget2 {
 private MyCodeRunner myCode = new MyCodeRunner();
 public void myMethod() {
  myCode .runMyCode();
 }
}

希望这是有道理的!