如果我们采用以下代码:
Shape p1 = new Square();
Square c1;
if(p1 instanceof Square) {
c1 = (Square) p1;
}
将多态性改为instanceof
是什么意思,顺便说一下,为什么它更好?
编辑:我了解多态性是什么;我缺少的是如何使用它而不是instanceof
。
答案 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();
Square
和Circle
都实现了getEdgesNumber()
方法,您只需调用它并根据具体实现获得结果。
你不需要知道你是在处理Square
还是Circle
,你只需要调用你需要的方法并依赖于对象的底层实现。
答案 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”。