将接口扩展为抽象类

时间:2012-10-01 12:52:31

标签: c# oop

我有一个应该移动某些形状的界面(移动)。

interface Move { move(); }
abstract class Shape : Move

class Circle : Shape
class Square : Shape
class Triangle : Shape

我的疑问是,我必须有一个移动Shapes的界面,但是只能移动Circle和Triangle,那么如何从Square中“删除”界面?我应该从Shape中删除界面并在Circle和Triangle上手动添加它吗?我有点困惑。希望有人可以帮助我。

6 个答案:

答案 0 :(得分:34)

你应该像这样设置你的课程:

interface IMovable { move(); } 
abstract class Shape : { } 

class Circle : Shape, IMovable { } 
class Square : Shape { } 
class Triangle : Shape, IMovable { } 

如果不能移动每个形状,则Shape不得实现界面。另请注意,我将您的界面重命名为IMovable,这不是一个大问题,但它更受欢迎,也是更好的命名惯例。

答案 1 :(得分:27)

您无法从继承树中删除接口。

您建模的内容似乎需要两个抽象类 - ShapeMovableShape

interface IMove { move(); } 
abstract class Shape : {} 
abstract class MovableShape : IMove, Shape {} 

class Circle : MovableShape{}
class Square : Shape{}
class Triangle : MovableShape{}

答案 2 :(得分:3)

您应该让自己更熟悉接口,类和OO背后的想法。您要说的是以下内容:

  • 每个形状都可以移动。
  • 广场是一种形状。
  • 但广场不能移动。

显然这没有道理。所以你必须调整你的课堂设计。每个形状都可以移动,Shape(和Square)应该实现Move,或者不能移动每个形状,然后Shape不应该实现Move。

答案 3 :(得分:3)

试试这个:

interface IMove { move(); }
abstract class Shape { }

class Circle : Shape, IMove { }
class Square : Shape { }
class Triangle : Shape, IMove { }

答案 4 :(得分:2)

其他选项可能只是在IMove.Move类中实现Shape方法,默认情况下会抛出NotSupportedException

public abstract class Shape : IMove 
{
     public virtual void Move()
     { 
         throw new NotSupportedException();
     }
}

所以在一天结束时,“任何形状都可以移动”,但“可移动的形状应该提供自己的移动方式”。

最后,让我们想象一下,有一堆形状以同样的方式移动。您将创建一个DefaultMovableShape抽象类派生Shape,它将覆盖Shape.Move虚拟方法。

public abstract class DefaultMovableShape 
{
     public override void Move()
     {
           // Do stuff
     }
}

答案 5 :(得分:2)

最佳答案取决于这些类的用例和环境。作为开发应用程序或框架的团队的一部分,采用该团队使用的设计模式比寻求完美的设计模式更可取。解决方案,因为它将使其他人更容易采用和维护您的代码。

您希望如何使用和扩展这些类也很重要。你会期待' Square'需要在将来移动? Shape的可移动性是否始终是静态的,还是作为动态属性更有用? Move()对于不是形状的类有什么价值吗?如果可移动性可用作动态属性,请考虑以下事项:

public abstract class Shape
{
     public bool isMovable()
     {
         return false;
     }

     public virtual void Move()
     { 
         if (!isMovable() {
             throw new NotSupportedException();
         } else {
             throw new BadSubclassException();
         }
     }
}

您的子类可以覆盖isMovable以提供静态或动态行为,并且可以进一步修改或子类化,只要您的文档明确指出isMoveable应始终在调用Move之前。默认行为应基于您希望使用代码的其他人的期望,具体取决于他们如何实施相关的设计模式。

通过查看集合类在不同框架中的可变性如何发展的历史,可以找到做出这些决策的挑战的一个很好的例子。有些设计中可变类(集合,数组,字典等)已经成为基类,在子类中实现了不变性,反之亦然。这两种方法都有有效的论据,也有动态方法,但对于框架用户来说,最重要的因素是 一致性, ,因为正确的是真正的关于什么是最容易使用的问题,提供安全性和性能不会受到影响。