如何使用多态而不是instanceof? (为什么?)

时间:2010-11-16 09:50:38

标签: java polymorphism instanceof

如果我们采用以下代码:

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

将多态性改为instanceof是什么意思,顺便说一下,为什么它更好?

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

7 个答案:

答案 0 :(得分:11)

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

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

  • 添加一种新的Shape(你有Square,Circle - 让我们添加Triangle):使用if-else解决方案你必须使用if-else查看所有现有的类,并为Triangle添加一个新的if分支;使用多态性,你只需添加一个新类并实现其中所有必需的方法。

所以,如果......其他......或多态:它取决于模块性。如果您希望以后添加许多新子类,请使用多态;如果您希望以后添加许多新方法,请使用if ... else ...,并在类中只放置最基本的方法,如访问器。或者换句话说:当你期望有很多if ... else ...分支时,你应该使用多态,当你期望很少这样的分支时,只要留下来,如果......其他......

另外:当你期望很少... else ...分支,但在很多地方,你应该考虑封装这个if ... else ...与访问者模式或只是用一个单独的案例制作一个枚举对于每个分支。

答案 1 :(得分:3)

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

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

在一个理想的世界中,我们不想担心我们正在处理的特定类型的对象,只有覆盖其界面中所有使用场景的更通用类型的接口。

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

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

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

答案 2 :(得分: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();

SquareCircle都实现了getEdgesNumber()方法,您只需调用它并根据具体实现获得结果。

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

另外,请查看how the docs are explaining it

答案 3 :(得分:1)

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

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

(假设Square当然延伸了形状)

不是很好吗?

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

答案 4 :(得分:0)

多态性允许您根据其类型更改某些内容的行为。不知道如何用你的例子解释它,因为你可以直接将它分配给Square如果由于某种原因重要的是它是Square。有时你需要子类,因为它可能有其他行为等,但请考虑这个例子:

class Shape
{
    abstract void draw();
}

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

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

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

Some people认为instanceof有时间和地点,并且访客模式不是总是完全和适当的替代品。其他一些人嘶嘶作响。冲洗,重复。

我认为你的例子可以通过尝试做一些有意义的(例如绘图或计算边等)来改进,因为OOP哲学将从根本上避免你在你的例子中说明的情况。例如,OOP设计会将c1声明为Shape而不是Square,或者只使用p1变量。

顺便说一句,如果你在c1为空的情况下,如果它不是Square,或者设置为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.

在我的观点中,它不比instanceof多OO,但我再也不认为instanceof是非“OO”。