使用instanceof
关键字反对object oriented programming
的本质?
我的意思是这是一个糟糕的编程习惯吗?
我在某处读到使用instanceof
关键字意味着设计可能不那么好。有没有更好的解决方法?
答案 0 :(得分:14)
一般来说是的。最好保留所有依赖于该类中特定类的代码,并且使用instanceof
通常意味着您已将某些代码放在该类之外。
看看这个非常简单的例子:
public class Animal
{
}
public class Dog extends Animal
{
}
public class Cat extends Animal
{
}
public class SomeOtherClass
{
public abstract String speak(Animal a)
{
String word = "";
if (a instanceof Dog)
{
word = "woof";
}
else if (a instanceof Cat)
{
word = "miaow";
}
return word;
}
}
理想情况下,我们希望所有针对狗的行为都包含在Dog类中,而不是传播到我们的程序中。我们可以通过重写我们的程序来改变它:
public abstract class Animal
{
public String speak();
}
public class Dog extends Animal
{
public String speak()
{
return "woof";
}
}
public class Cat extends Animal
{
public String speak()
{
return "miaow";
}
}
public class SomeOtherClass
{
public String speak(Animal a)
{
return a.speak();
}
}
我们已指定Animal
必须使用speak
方法。现在SomeOtherClass
不需要知道每种动物的具体细节 - 它可以将其移交给Animal
的子类。
答案 1 :(得分:4)
推广虚拟方法有许多好的答案,但instanceof
也有其用途。想象一下,您迭代List<Event>
,以获取所有Urgent
个对象。你可以使用isUrgent()
来做,但我不确定它是否必须更简洁或可读。此外,isUrgent()
要求Event
知道其子类可能拥有相应的属性,这可能是:
Event
属于某个无法修改的库,则
答案 2 :(得分:3)
支持多态和动态绑定到向下转换和instanceof
。这是“OO Way”,使您能够编写不需要了解子类型的代码。
示例强>
abstract class Animal {
public abstract void talk();
//...
}
class Dog extends Animal {
public void talk() {
System.out.println("Woof!");
}
//...
}
class Cat extends Animal {
public void talk() {
System.out.println("Meow!");
}
//...
}
class Hippopotamus extends Animal {
public void talk() {
System.out.println("Roar!");
}
//...
}
class Main {
public static void main(String[] args) {
makeItTalk(new Cat());
makeItTalk(new Dog());
makeItTalk(new Hippopotamus());
}
public static void makeItTalk(Animal animal) {
animal.talk();
}
}
答案 3 :(得分:3)
当通过虚拟方法实现相同的效果时,不鼓励使用instanceof
,例如thomson_matt。
但是,在某些情况下有必要使用instanceof
。例如,当您的代码从外部源获取Object时,例如,返回Object
的网络或第三方API,您必须确定此Object的类型并采取相应的行动。
答案 4 :(得分:3)
关键是不要将instanceof视为常见“常规练习”的一部分。与一般的内省一样,instanceof是一种特殊的工具,特别适用于非典型情况。每当你使用'instanceof'时,你也可能会发现自己正在使用平台的其他“特殊”部分,例如更常见的反射。
只要你发现自己使用它,你就会接受你所做的事情,如果没有更优雅/实用的替代方案,你所做的就是一件好事,那就没关系了。
尽管如此,日常计划中最典型的情况可能是:
您可以尝试并坚持的经验法则是不要求库的用户必须使用'instanceof',而是在库内部具有“instanceof”的任何情况。
或者换句话说,你应该重新构建你的问题:“'intsanceof'是 的解决方法是什么?”
答案 5 :(得分:2)
这是不鼓励的,因为人们可能会用它来做这样的事情:
if( myAnimal instanceof Dog )
((Dog)myAnimal).bark();
else( myAnimal instanceof Cat )
((Cat)myAnimal).meow();
相反,Animal
应该有一个speak()
方法Dog
和Cat
继承。在具有多态性和动态绑定的适当OOP中,您只需执行
myAnimal.speak();
但是,在某些情况下,您必须使用instanceof
来确定对象的特定类型。也许你家里有一个Animals
的列表,walk()
中你唯一想要的是Dog
。在这种情况下,您将遍历您的列表并且只会walk()
狗。
答案 6 :(得分:0)
创建工厂的情况如何(见下文)? 在这种情况下,我不认为Animal子类知道如何为自己构建一个笼子是合适的。它似乎超出了Animal的范围,并迫使Animal子类采取不是Animal所固有的行为。
public static Cage createCage(Animal animal) {
if (animal instanceof Dog)
return new DogHouse();
else if (animal instanceof Lion)
return new SteelCage();
else if (animal instanceof Chicken)
return new ChickenWiredCage();
else if (animal instanceof AlienPreditor)
return new ForceFieldCage();
...
else
return new GenericCage();
}
答案 7 :(得分:0)
instaceOf操作的另一种用法可能是错误处理。如果您对异常有类似的错误处理,并且您希望将它们全部放在一个地方,则可以使用:
public void handleError(Throwable t, HttpServletRequest req) {
if (t instaceOf ValidationException) {
...doSomewthing......
} else if (t instaceOf DataException) {
...doSomewthing......
} else if (t instaceOf DataException) {
...doSomewthing......
} else {
...doSomewthing......
}
}
使用上面的代码,你可以避免有很多
} catch <Exception> {
阻止而只有一个
} catch (Throwable t) {
handleError(t, request);
return "errorPage" or whateveryouwant;
}
另外,还有一件事是,你检查java源代码,你会发现很多用法的用法..
一个好的链接: article about usage of instaceof