由于多重继承是不好的(它使源代码更加复杂),c#没有直接提供这样的模式。但有时候拥有这种能力是有帮助的。
例如,我能够使用接口和三个类实现缺少的多重继承模式:
public interface IFirst { void FirstMethod(); }
public interface ISecond { void SecondMethod(); }
public class First:IFirst
{
public void FirstMethod() { Console.WriteLine("First"); }
}
public class Second:ISecond
{
public void SecondMethod() { Console.WriteLine("Second"); }
}
public class FirstAndSecond: IFirst, ISecond
{
First first = new First();
Second second = new Second();
public void FirstMethod() { first.FirstMethod(); }
public void SecondMethod() { second.SecondMethod(); }
}
每当我向其中一个接口添加方法时,我也需要更改类FirstAndSecond。
是否有一种方法可以像在c++中那样将多个现有类注入到一个新类中?
也许有一种使用某种代码生成的解决方案?
或者它看起来像这样(虚构的c#语法):
public class FirstAndSecond: IFirst from First, ISecond from Second
{ }
这样,当我修改其中一个接口时,就不需要更新类FirstAndSecond。
EDIT
也许考虑一个实际的例子会更好:
您有一个现有的类(例如,基于ITextTcpClient的基于文本的TCP客户端),您已经在项目中的不同位置使用它。现在,您觉得有必要创建一个类的组件,以便windows窗体开发人员可以轻松访问。
据我所知,你目前有两种方法来做到这一点:
编写一个从组件继承的新类,并使用类本身的实例实现TextTcpClient类的接口,如FirstAndSecond所示。
编写一个继承TextTcpClient的新类,并以某种方式实现IComponent(实际上还没有尝试过这个)。
在这两种情况下,您都需要为每个方法而不是每个类做工作。因为你知道我们将需要TextTcpClient和Component的所有方法,所以将这两个方法合并到一个类中是最简单的解决方案。
为了避免冲突,这可以通过代码生成来完成,结果可以在之后修改,但手动输入这是一个纯粹的痛苦。
我创建了一个c#后编译器来实现这类事情:
using NRoles;
public interface IFirst { void FirstMethod(); }
public interface ISecond { void SecondMethod(); }
public class RFirst : IFirst, Role {
public void FirstMethod() { Console.WriteLine("First"); }
}
public class RSecond : ISecond, Role {
public void SecondMethod() { Console.WriteLine("Second"); }
}
public class FirstAndSecond : Does<RFirst>, Does<RSecond> { }
你可以将后编译器作为Visual Studio post-build-event运行:
C: \ some_path \ nroles-v0.1.0-bin \ nutate.exe " $(定位路径)"
在同一个程序集中,你可以这样使用它:
var fas = new FirstAndSecond();
fas.As<RFirst>().FirstMethod();
fas.As<RSecond>().SecondMethod();
在另一个程序集中,你像这样使用它:
var fas = new FirstAndSecond();
fas.FirstMethod();
fas.SecondMethod();
由于多重继承(MI)的问题时常出现,我想添加一种方法来解决组合模式的一些问题。
我建立在IFirst, ISecond,First, Second, firststandsecond方法的基础上,就像问题中提到的那样。我将示例代码减少到IFirst,因为无论接口/ MI基类的数量如何,模式都保持不变。
让我们假设,MI First和MI Second都派生自同一个基类BaseClass,只使用BaseClass中的公共接口元素
这可以通过在第一个和第二个实现中向BaseClass添加容器引用来表示:
class First : IFirst {
private BaseClass ContainerInstance;
First(BaseClass container) { ContainerInstance = container; }
public void FirstMethod() { Console.WriteLine("First"); ContainerInstance.DoStuff(); }
}
...
当引用BaseClass中受保护的接口元素时,或者当First和Second是MI中的抽象类时,要求它们的子类实现一些抽象部分,事情就变得更加复杂了。
class BaseClass {
protected void DoStuff();
}
abstract class First : IFirst {
public void FirstMethod() { DoStuff(); DoSubClassStuff(); }
protected abstract void DoStuff(); // base class reference in MI
protected abstract void DoSubClassStuff(); // sub class responsibility
}
c#允许嵌套类访问其包含类的受保护/私有元素,因此这可以用于链接来自第一个实现的抽象位。
class FirstAndSecond : BaseClass, IFirst, ISecond {
// link interface
private class PartFirst : First {
private FirstAndSecond ContainerInstance;
public PartFirst(FirstAndSecond container) {
ContainerInstance = container;
}
// forwarded references to emulate access as it would be with MI
protected override void DoStuff() { ContainerInstance.DoStuff(); }
protected override void DoSubClassStuff() { ContainerInstance.DoSubClassStuff(); }
}
private IFirst partFirstInstance; // composition object
public FirstMethod() { partFirstInstance.FirstMethod(); } // forwarded implementation
public FirstAndSecond() {
partFirstInstance = new PartFirst(this); // composition in constructor
}
// same stuff for Second
//...
// implementation of DoSubClassStuff
private void DoSubClassStuff() { Console.WriteLine("Private method accessed"); }
}
这里涉及到相当多的样板文件,但是如果FirstMethod和SecondMethod的实际实现足够复杂,并且访问的私有/受保护方法的数量适中,那么这种模式可能有助于克服缺乏多重继承的问题。