19

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

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

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

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

4

6 回答 6

34

你应该像这样设置你的类:

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

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

如果不是每个形状都可以移动,那么Shape就不能实现接口。另请注意,我将您的界面重命名为IMovable,这不是什么大不了的事,但它更容易被接受并且命名约定更好。

于 2012-10-01T12:54:35.237 回答
27

您不能从继承树中删除接口。

您的模型似乎需要两个抽象类 -ShapeMovableShape.

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

class Circle : MovableShape{}
class Square : Shape{}
class Triangle : MovableShape{}
于 2012-10-01T12:55:36.060 回答
3

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

  • 每个形状都可以移动。
  • 正方形是一种形状。
  • 但是 Square 不能移动。

显然这是没有意义的。所以你必须调整你的班级设计。要么每个形状都可以移动,Shape(和 Square)应该实现 Move,或者不是每个形状都可以移动,那么 Shape 不应该实现 Move。

于 2012-10-01T12:56:03.137 回答
3

试试这个:

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

class Circle : Shape, IMove { }
class Square : Shape { }
class Triangle : Shape, IMove { }
于 2012-10-01T12:56:16.883 回答
2

其他选项可能只是IMove.Move在类中实现方法Shape并默认抛出一个NotSupportedException

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

因此,归根结底,“任何形状都可以是可移动的”,但“可移动的形状应该提供自己的移动实现方式”。

最后,让我们假设有一堆形状以相同的方式移动。您将创建一个DefaultMovableShape抽象类 deriving Shape,它会覆盖Shape.Move虚拟方法。

public abstract class DefaultMovableShape 
{
     public override void Move()
     {
           // Do stuff
     }
}
于 2012-10-01T13:04:51.790 回答
2

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

您期望如何使用和扩展这些类也很重要。您认为“Square”将来需要可移动吗?Shape 的可移动性总是静态的,还是作为动态属性更有用?Move() 对非 Shapes 的类有任何价值吗?如果可移动性可用作动态属性,请考虑:

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 之前。默认行为应该基于您期望使用您的代码的其他人的期望,基于他们如何实现相关的设计模式。

通过查看集合类的可变性在不同框架中如何演变的历史,可以找到做出这些决定所面临挑战的一个很好的例子。有些设计将可变类(集合、数组、字典等)作为基类,在子类中实现不变性,反之亦然。这两种方法以及动态方法都有有效的论据,但对于框架的用户来说,最重要的因素是一致性,因为正确的实际上是最容易使用的问题,提供安全性和性能不是妥协。

于 2012-10-01T17:47:18.547 回答