2012-10-01 119 views
19

我有一个接口(移动),应该移动一些形状。将接口扩展到抽象类

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

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

我的疑问是,我必须有它移动的形状,但只有圆形和三角形应该能够移动的界面,让我怎么“删除”,从广场的界面?我应该从Shape中移除界面并在Circle和Triangle上手动添加它吗?我有点困惑于此。希望有人能帮助我。

回答

34

,您应该设置你的类是这样的:

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

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

如果不是每一个形状可以移动,然后Shape不得实现的接口。另外请注意,我将您的界面重命名为IMovable,这不是什么大问题,但它更受欢迎,而且命名规则更好。

+4

这个。 “如何不继承一些基本行为”这个问题的答案始终是“不要从一开始就继承它”。 – KeithS

+0

@KeithS,这是正确的。停止继承只是看待继承的反面。所以,希望这会帮助OP认为前进的另一种方式。 :) –

+4

@Mike,'IMovable'怎么样? – smartcaveman

27

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

你模型似乎需要两个抽象类 - ShapeMovableShape

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

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

这应该是公认的答案。 –

+3

@NadirSampaoli,你__opinion__得到足够的重视,但要小心,因为这会变成一个非常主观的谈话。有一点需要注意的是__I + 1也是这个答案,因为它非常正确。 –

+3

@Mike我很抱歉,其实我的评论听起来很大胆;我应该附加一个“在我看来”。 –

3

你应该让自己更熟悉接口,类和面向对象的概念。你要告诉的是以下内容:

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

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

3

尝试了这一点:

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

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

其他选项可能只是落实在ShapeIMove.Move方法,默认情况下抛出NotSupportedException。所以在一天结束时,“任何形状都可以移动”,但“可移动的形状应该提供它自己的如何移动它的实现”。

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

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

虽然这可行,但我建议不要这样做除非你的'Move'函数的规范明确地在界面层声明'Move'会在它不适用于底层对象的情况下抛出一个异常。当然,在这一点上,您应该质疑为什么它实现了界面,并且您可能有设计问题(请参阅接受的答案)。 – Anthony

+0

@Anthony我同意了。我只是想给出一个选择。我相信有理由认为接受的答案是正确的做法,但是在某些情况下,我也可以完成这项工作。这取决于你如何看待问题:“形状不可移动”或“形状可移动”。 –

+0

@Anthony我仔细检查了你的评论。这个声明应该在'Shape'类文档或'IMove'中。形状“可能会移动”,因为Shape可以提供“如何移动”的实现。所以如果你想移动一个无法移动的Shape,那么这个Shape“不支持移动”。 –

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提供静态或动态行为,可以进一步修改或子类随着时间的推移,只要你的文档使清楚的是,移动应始终在移动的调用之前。默认行为应基于您期望使用您的代码的其他人的期望,这取决于他们如何实施相关设计模式。

作出这些决定的挑战的一个很好的例子,可以通过查看如何集合类的易变性在不同的框架已经进化历史中找到。已经有设计将可变类(集合,数组,字典等)作为基类,在子类中实现了不变性,以及相反。有两种方法,以及一个动态的方法有效参数,但对于一个框架,用户最重要的因素是一致性,因为什么是正确的是真的,什么是最简单的事来使用,提供安全性能不会受到影响。