Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从面向对象的角度来看,动态多态性、抽象类和接口之间有什么区别,如C#所反映的?_C#_Oop_Interface_Polymorphism_Abstract Class - Fatal编程技术网

从面向对象的角度来看,动态多态性、抽象类和接口之间有什么区别,如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 */ }
}
  • 除了逻辑上的差异,我还想知道C#中具体反映的技术差异(因此,这不是一个问题)
  • 有点类似,但它询问方法,而我询问类,所以它不是重复的

  • 圆形
    矩形
    是形状。两者都有周长和面积,但用于计算周长和面积的实现不同。我可以看到三种不同的方法来实现这种逻辑,我不确定这些方法之间的区别

    使用动态多态性:

    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