从面向对象的角度来看,动态多态性、抽象类和接口之间有什么区别,如C#所反映的?
注意事项:从面向对象的角度来看,动态多态性、抽象类和接口之间有什么区别,如C#所反映的?,c#,oop,interface,polymorphism,abstract-class,C#,Oop,Interface,Polymorphism,Abstract Class,注意事项: class Shape { public virtual double Perimeter() { /* logic */ } public virtual double Area() { /* logic */ } } class Rectangular : Shape { public override double Perimeter() { /* logic */ } public override double Area() { /* lo
class Shape
{
public virtual double Perimeter() { /* logic */ }
public virtual double Area() { /* logic */ }
}
class Rectangular : Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
class Circle : Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
abstract class Shape
{
public abstract double Perimeter() {}
public abstract double Area() {}
}
class Rectangular : Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
class Circle: Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
interface IShape
{
double Perimeter();
double Area();
}
class Rectangular : IShape
{
public double Perimeter() { /* logic */ }
public double Area() { /* logic */ }
}
class Circle: IShape
{
public double Perimeter() { /* logic */ }
public double Area() { /* logic */ }
}
圆形
和矩形
是形状。两者都有周长和面积,但用于计算周长和面积的实现不同。我可以看到三种不同的方法来实现这种逻辑,我不确定这些方法之间的区别
使用动态多态性:
class Shape
{
public virtual double Perimeter() { /* logic */ }
public virtual double Area() { /* logic */ }
}
class Rectangular : Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
class Circle : Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
abstract class Shape
{
public abstract double Perimeter() {}
public abstract double Area() {}
}
class Rectangular : Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
class Circle: Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
interface IShape
{
double Perimeter();
double Area();
}
class Rectangular : IShape
{
public double Perimeter() { /* logic */ }
public double Area() { /* logic */ }
}
class Circle: IShape
{
public double Perimeter() { /* logic */ }
public double Area() { /* logic */ }
}
使用抽象类:
class Shape
{
public virtual double Perimeter() { /* logic */ }
public virtual double Area() { /* logic */ }
}
class Rectangular : Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
class Circle : Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
abstract class Shape
{
public abstract double Perimeter() {}
public abstract double Area() {}
}
class Rectangular : Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
class Circle: Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
interface IShape
{
double Perimeter();
double Area();
}
class Rectangular : IShape
{
public double Perimeter() { /* logic */ }
public double Area() { /* logic */ }
}
class Circle: IShape
{
public double Perimeter() { /* logic */ }
public double Area() { /* logic */ }
}
使用接口:
class Shape
{
public virtual double Perimeter() { /* logic */ }
public virtual double Area() { /* logic */ }
}
class Rectangular : Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
class Circle : Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
abstract class Shape
{
public abstract double Perimeter() {}
public abstract double Area() {}
}
class Rectangular : Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
class Circle: Shape
{
public override double Perimeter() { /* logic */ }
public override double Area() { /* logic */ }
}
interface IShape
{
double Perimeter();
double Area();
}
class Rectangular : IShape
{
public double Perimeter() { /* logic */ }
public double Area() { /* logic */ }
}
class Circle: IShape
{
public double Perimeter() { /* logic */ }
public double Area() { /* logic */ }
}
在标题中,我提到我对从OOP的角度给出答案很感兴趣。我想了解基于OOP范式的两种方法之间的理论差异,并从中了解技术差异。例如,我知道接口方法不能有一个实现,而虚拟方法可以,但我不理解为什么它与OOP范式一致
请回答所有的理论差异,对于每个差异,用C#表示衍生的技术差异
非常感谢
编辑: @AdrianoRepetti和@bickets说我的问题很模糊。我的英语不是很好,所以我会尽可能清楚地解释我自己 我展示了做同一件事的三种不同方式。但这真的是一回事吗?从项目架构POV来看,它们之间有什么不同?我的意思是,当我设计程序时,为什么我要选择一个呢?什么是本质上的区别,这些区别是如何用C#的语法表达的?我希望我的问题现在更清楚了 如果说一口流利英语的人认为他/她理解我的问题,并能将其编辑得更清晰、语法正确,我将不胜感激 非常感谢 简而言之: 使用动态多态性:当基类具有可由子类更改的实现时,使用此选项。这个类可以完全功能化,而不需要子类 使用抽象类:如果要强制子类来实现功能。基类不够完整,无法将其创建为独立对象 使用接口:如果要为此类使用约定。使用它使类“兼容”,以便其他“理解”接口的类(部分)可以使用该功能
在您的案例中,我将创建一个接口
IShape
,因为(基本)形状
本身无法实现面积
计算方法(因此它不应该是动态多态性),您也不需要形状本身的任何状态信息。(通常是抽象类)所有计算变量都在(子)类本身中实现。与矩形(宽度/高度)和圆形半径等类似。接口
的优点是,可以实现多个接口
如果
形状
是一个控件,则故事会发生变化…您的三种方法完全不同,因此无法真正比较它们。让我们看看原因
非抽象基类
您有一个基类,但它不是抽象的,它提供了一个默认实现。你应该问自己的第一个问题是这是否有意义
Shape shape = new Shape();
Console.WriteLine($"Area of this shape is {shape.Area}");
- 是否存在通用的
形状
- 你们能计算出一个未知形状的面积吗
Circle circle = new Circle();
Shape shape = circle;
// When invoking with a Shape instance you will call
// be class method, when with a Circle instance you will call derived
// class method!!!
Debug.Assert(shape.Area != circle.Area);
还要注意的是,基类为区域
和周长
提供了一个实现,它对一般形状有意义吗
接口
在这种情况下,IMO接口(或抽象基类)才有意义。简单地说,您只需要一个接口来访问形状对象,而不提供通用(不存在?)实现,调用的方法可能是您所期望的
缺点?假设您稍后将IEnumerable GetPoints()
方法添加到IShape
,为简单起见,假设当实现无法返回多段线来绘制此形状时,此方法可能返回null
。现在,在更新所有实现IShape
的类之前,您的代码一直处于中断状态。如果您将IShape
部署为库的一部分,那么您也引入了一个突破性的更改(我在这里不重复太多,其他地方已经广泛讨论过)
一个注意事项(即使我理解这只是一个虚构的例子):所有形状都存在面积吗?如果引入开放多段线会怎么样?在这种情况下,接口更有意义:
interface IShape
{
double Perimiter { get; }
}
interface IClosedFigure : IShape
{
double Area { get; }
}
interface IHasPoints
{
IEnumerable<Point> GetPoints();
}
sealed class Circle : IClosedFigure { /* ... */ }
sealed class Polyline : IShape, IHasPoints { /* ... */ }
请注意,如果将方法标记为abstract
,则仍然可以添加方法并引入中断更改。缺点?您现在强制使用基类,而C#是单继承
请注意,您不需要只有抽象方法/属性,您可以为其中的一些/所有方法/属性提供实现。在这种情况下,这种方法更类似于您第一次提出的方法
结论
第二种方法非常简单,应该很少在设计良好的体系结构中使用。第一种方法可能在某些情况下有意义,并且您可以提供合理的默认实现(例如,您可以使用慢速方法,通过GetPoints()
,计算面积,并为已知形状提供更快的计算)。如果基类应为n