我是C#的新手。我了解到一个派生类只能有一个基类。在我看来,这是C#的一个弱点,但也许我做得不对。我正在寻找";最好的";解决方案,以绕过这一点,同时尊重DRY和clean代码原则。下面我创建了一个例子,我最终从两个类中派生出了这个想法。有两个明显的解决方案:
- 将
CColor
的成员和方法实现两次到CColoredRectangle
和CColoredTriangle
中。但这违反了DRY原则 - 将
CColor
的成员和方法实现为CShape
(或者派生一个CColoredShape
类作为其他类的基础)。但是CColor
方法在CRectangle
和CTriangle
中是可用的,其中它们不应该存在。这违背了干净代码的思想
接口不能完成任务,因为它们不允许成员。有什么优雅的解决方案吗?提前谢谢。
public abstract class CShape
{
private double x,y;
protected CShape(double x, double y)
{
this.x = x;
this.y = y;
}
public abstract double Area { get; }
public class CRectangle : CShape
{
protected CRectangle(double x, double y) : base(x, y) { }
public override double Area => x * y;
}
public class CTriangle : CShape
{
protected CTriangle(double x, double y) : base(x, y) { }
public override double Area => x * y * 0.5;
}
public class CColor
{
public int R,G,B; //I need members here, so an interface won't work
public void MixColorWith(int r,int g,int b) { /*Code....*/}
}
public class CColoredTriangle : CTriangle, CColor //compiler error CS1721
{
}
public class CColoredRectangle : CTriangle, CColor //compiler error CS1721
{
}
}
让我们回顾一下在你看来哪些事情是正确的,以便能够量化这是C#的弱点的说法,同样在你看来。
你假设一个彩色三角形就是一种颜色。这就是继承的意义,它是一种"继承";is-a";关系虽然存在一些不是彩色三角形的颜色,但你可以假设至少有一些颜色是彩色三角形。我们在这里意见一致吗?
因此,我的观点是:不存在一种颜色是彩色三角形。不存在";is-a";这里的关系。你可能能够证明这样一个事实,即彩色三角形";有一个";颜色,在这种情况下,您将向其添加Color
属性,但仅限于此。
因此,您的问题不需要钻石(多重)继承。
编辑:还有你假设的另一件事,"我需要这里的成员,所以接口不起作用",从两方面来看都是完全错误的。在C#中,接口可以同时具有属性和方法。
一般来说,大多数专家都说你应该"偏爱组合而非继承">
在这种情况下,这几乎是正确的做法
CColoredTriangle
不是CColor
,它有一个CColor
,因此它应该只是它的一个属性。
考虑到您似乎也希望能够通过对象具有CColor
这一事实来引用对象,而不管它们是什么形状,创建IHasColor
接口是有意义的
public abstract class CShape
{
private double x,y;
protected CShape(double x, double y)
{
this.x = x;
this.y = y;
}
public abstract double Area { get; }
public class CRectangle : CShape
{
protected CRectangle(double x, double y) : base(x, y) { }
public override double Area => x * y;
}
public class CTriangle : CShape
{
protected CTriangle(double x, double y) : base(x, y) { }
public override double Area => x * y * 0.5;
}
public class CColor
{
public int R,G,B;
public void MixColorWith(int r,int g,int b) { /*Code....*/}
}
public interface IHasColor
{
CColor Color {get; set;}
}
public class CColoredTriangle : CTriangle, IHasColor
{
CColor Color {get; set;}
}
public class CColoredRectangle : CTriangle, IHasColor
{
CColor Color {get; set;}
}
}