15

如果我们采用下面的代码:

Shape p1 = new Square();
Square c1;
if(p1 instanceof Square) {
  c1 = (Square) p1;
}

更喜欢多态性是什么意思instanceof,顺便说一句,为什么它更好?

编辑: 我明白什么是多态性;我缺少的是如何使用它而不是instanceof.

4

7 回答 7

13

if...else...(或 switch,或 Visitor)与多态性之间的主要区别在于模块化。有所谓的开闭原则,基本上就是说,当你在现有程序中添加新功能时,你对现有代码所做的更改越少越好(因为每次更改都需要一些工作,并且可能会引入错误)。所以让我们比较一下变化的数量:

  • 添加新方法(例如,您有paint() 和getArea(),让我们添加getCircumference()):使用if-else 解决方案您只需更改一个文件- 将包含新方法的文件。使用多态性,您必须更改 Shape 类的所有实现。

  • 添加一种新的形状(您有 Square、Circle - 让我们添加 Triangle):使用 if-else 解决方案,您必须使用 if-else 检查所有现有类并为 Triangle 添加新的 if 分支;对于多态性,您所拥有的只是添加一个新类并在其中实现所有必需的方法。

所以 if...else... 或多态性:它取决于模块化。如果您预计以后会添加许多新的子类,请使用多态性;如果您希望稍后会添加许多新方法,请使用 if...else...,并且在类中仅放置最“基本”的方法,例如访问器。或者换句话说:当你期望有很多 if...else... 分支时,你应该使用多态性,当你期望这样的分支很少时,就留在 if...else...

另外:当您期望很少的 if...else... 分支,但在很多地方,您应该考虑使用访问者模式封装这个 if...else... 或者只是为每个分支创建一个带有单独案例的枚举.

于 2010-11-16T10:50:35.743 回答
3

这个想法是你不应该关心你正在处理什么样的形状。例如,如果 Shape 定义了一个抽象的 draw() 方法,那么三角形、正方形和任何其他扩展 Shape 的东西也将具有相同的方法。

多态性的一个简单定义是“将不同类型视为相同”,即使用相同的接口。

在一个理想的世界里,我们不想担心我们正在处理的对象是什么具体类型,只需要一个更通用的类型的接口,在它的接口中涵盖所有使用场景。

Shape p1 = new Square();
Shape p2 = new Triangle();
p1.draw();
p2.draw();

在这段代码中,我们直接在 p1 和 p2 上调用 Shape.draw()。我们不关心实现类做了什么,只关心接口(或抽象父类)定义了什么。

编辑:关于问题中的示例,通常建议通过尽可能封装行为来避免这种代码模式。使用 instanceof 可以被认为是代码异味,因为每当您添加新类时,您都必须更新所有条件。

于 2010-11-16T09:59:51.267 回答
2

考虑以下

abstract class Shape {
   public abstract int getEdgesNumber();
}

class Square extends Shape {
    public int getEdgesNumber(){
        return 4;
    }
}

class Circle extends Shape {
    public int getEdgesNumber(){
        return 1; //not so sure it counts as one but for the example is fine ^^'
    }
}     

Shape square = new Square();
int squareEdgesNumber = square.getEdgesNumber();

Shape circle = new Circle();
int circleEdgesNumber = circle.getEdgesNumber();

ASquare和 aCircle都实现了该getEdgesNumber()方法,您只需根据特定的实现调用它并获取结果。

你不需要知道你是在处理 aSquare还是 a Circle,你只需调用你需要的方法并依赖于对象的底层实现。

另外,看看文档是如何解释它的

于 2010-11-16T09:57:07.917 回答
1

这并不是一个很好的例子,但这就是您的代码的样子。

Square c1 = new Square();
Shape p1 = c1;

(当然,考虑到 Square 扩展了 Shape )

好多了不是吗?

至于“为什么更好”,其他答案给出了一些要点。

于 2010-11-16T09:59:10.410 回答
0

多态性使您可以根据某物的类型来更改某物的行为。不知道如何用你的例子来解释它,因为如果出于某种原因它是一个 Square 很重要,你可以直接将它分配给一个 Square。有时您需要子类化,因为它可能具有其他行为等,但请考虑以下示例:

class Shape
{
    abstract void draw();
}

class Square extends Shape
{
    void draw()
    {
        // square drawing goes here
    }
}

这里的 draw 方法是多态性的一个例子,因为我们有一个基类 Shape,它说现在所有的形状都如何绘制自己,但只有 Square 知道如何绘制 Square。

于 2010-11-16T09:57:31.847 回答
0

我假设“Shape”是一个接口,而“Square”是该接口的一个实现。

现在,如果您需要调用为 Shape 接口声明的方法(典型示例是 Shape.getArea()),您不应该关心它是 Square 还是其他东西,而是调用该函数。

于 2010-11-16T09:57:59.153 回答
0

有些人认为 有时间和地点instanceof,并且访问者模式并不总是完整且适当的替代品。其他一些人嘶嘶作响,皱着眉头。冲洗,重复。

我认为您的示例可以通过尝试做一些有意义的事情(例如绘图或计算边等)来改进,因为 OOP 哲学将从根本上避免您在示例中说明的情况。例如,OOP 设计要么声明c1为 aShape而不是 a Square,要么简单地使用p1变量。

顺便说一句,如果您遇到 c1 如果不是 Square 则为 null 或设置为 p1 如果是的话,则存在类似的“as”运算符,我很喜欢。

Shape p1  = (Math.random()>0.5) ? new Square() : new Circle();
Square c1 = p1 as Square;
// c1 is null or not, depending on p1's type.

在我看来,这并不比 OO 多instanceof,但话又说回来,我真的不认为instanceof是天生的“非 OO”。

于 2012-03-27T03:15:24.187 回答