2011-07-06 24 views
10

¿Está usando la palabra clave instanceof contra la esencia de object oriented programming? Quiero decir, ¿es una mala práctica de programación? Leí en alguna parte que el uso de la palabra clave instanceof significa que el diseño puede no ser tan bueno. ¿Alguna mejor solución?instancia del uso de la palabra clave

+0

¿Cuál es la instancia en la que lo está utilizando? Es difícil proporcionar una solución si el problema no aparece en la lista. – Kal

+0

@aps ¿puede mostrar el uso de 'instanceof' que le preocupa? –

+0

No lo estoy usando. Pero solo pregunto por qué no se considera una programación tan buena si alguien usa instanceof. – aps

Respuesta

14

Hablando en general sí. Lo mejor es mantener todo el código que depende de ser una clase específica dentro de esa clase, y usar instanceof generalmente significa que has puesto algún código fuera de esa clase.

mirada a este ejemplo muy simple:

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; 
    } 
} 

Idealmente, nos gustaría que todo el comportamiento que es específico para los perros que se encuentran en la clase de perro, en lugar de difusión en todo nuestro programa. Podemos cambiar eso reescribiendo nuestro programa como este:

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(); 
    } 
} 

Hemos determinado que un Animal tiene que tener un método speak. Ahora, SomeOtherClass no necesita conocer los detalles particulares de cada tipo de animal; puede entregarlo a la subclase Animal.

+2

Sólo como un extra punto: Como se dijo en esta respuesta, un problema con 'instanceof' es que necesita especificar el subtipo. ¿Qué pasa si los subtipos cambian? Entonces necesita volver a escribir las pruebas 'instanceof'. Pero si usa un enlace dinámico y un polimorfismo, no hará la diferencia y seguirá funcionando. – adamjmarkham

+0

+1: Debido a la parte de "cómo se debe realmente hacer": D –

+0

¿Debe 'hablar' ser' abstracto' en Animal, o todos los animales comienzan a silenciarse? –

2

Está desanimado porque la gente puede utilizar para hacer algo como esto:

if(myAnimal instanceof Dog) 
    ((Dog)myAnimal).bark(); 
else(myAnimal instanceof Cat) 
    ((Cat)myAnimal).meow(); 

En cambio, Animal debe tener un método speak() cuales Dog y Cat hereda. En programación orientada a objetos apropiada con el polimorfismo y la dinámica de unión, usted entonces sólo tiene que hacer

myAnimal.speak(); 

Sin embargo, hay algunos casos en los que se debe utilizar instanceof para determinar el tipo específico de un objeto. Quizás tenga una lista de Animals en su casa y los únicos que desee sacar por walk() son Dog s. En ese caso, recorrería su lista y solo walk() los perros.

+2

Me encanta el hecho de que estábamos escribiendo estos al mismo tiempo y ambos fueron para ejemplos de animales :) –

+2

Estaba a punto de comentar exactamente lo mismo en su publicación al igual que usted comentó sobre el mío :) – tskuzzy

3

Favorece el polimorfismo y el enlace dinámico a la bajada y instanceof. Esta es la "OO Way" y le permite escribir código que no necesita saber acerca de los subtipos.

Ejemplo

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(); 
    } 
} 
+2

Creo que 'abajo' sería un fonema más apropiado para un hipopótamo :). Voy a subclasificar y anular el comportamiento predeterminado. +1 para su diseño que me permite también. – Perception

3

Uso de instanceof se desaconseja cuando mismo efecto se puede lograr a través de métodos virtuales, como en el ejemplo de thomson_matt. Sin embargo, es necesario utilizar instanceof en algunas circunstancias. Por ejemplo, cuando su código obtiene un Objeto de una fuente externa, por ejemplo, API de red o de un tercero que devuelve Object, debe decidir cuál es el tipo de este Objeto y actuar de forma adecuada.

4

Hay muchas buenas respuestas que promueven los métodos virtuales, pero instanceof tiene su uso también. Imagine que itera sobre List<Event>, para recoger todos los objetos Urgent. Puede hacerlo usando isUrgent(), pero no estoy seguro si fue necesariamente más conciso o legible.Además, isUrgent() requeriría que Event tenga en cuenta que sus subclases pueden poseer la propiedad respectiva, que podría:

  • considerarse como algo en contra de los principios de modularidad;
  • ser incluso imposible, si Event pertenece a alguna biblioteca que no se puede modificar.
  • 3

    La clave es no ver instancias como parte de una "práctica normal" común. Al igual que la introspección en general, instanceof es una herramienta especial para usar en circunstancias atípicas particulares. Siempre que use 'instanceof', también puede encontrarse utilizando otras partes 'especiales' de la plataforma, como la reflexión en general.

    Siempre y cuando te encuentres utilizándote aceptas que lo que estás haciendo es un desafío en ausencia de una alternativa más elegante/práctica, entonces está bien.

    Dicho esto, las circunstancias más típicas de los programas de todos los días son probablemente:

    • iguales de ejecución()
    • lectura objetos serializados
    • algunos otros casos en los que le den una serie/colección de artículos, por ejemplo enumerar JComponents en un marco/contenedor y luego tomar medidas dependiendo del tipo.

    Una regla de oro que podría intentar y atenerse es no requerir que los usuarios de una biblioteca tengan que usar 'instanceof', sino que tengan casos de 'instancia de' internos en la biblioteca.

    O dicho de otra manera, debe volver a enmarcar su pregunta: "¿Cuáles son los casos en que 'intsanceof' es una solución para?"

    +0

    thomson_matt ha dado un buen ejemplo de mal uso de instanceof. Ahora tengo una situación, donde todas las condiciones que dijo, son ciertas. Say Animal es la clase abstracta, Cat y Dog son sus subclases. Entonces, naturalmente, el sonido que cada animal debería hacer debe ser encapsulado en su propia clase. Pero digamos que tengo otra clase llamada Mouse que reacciona a diferentes animales de diferentes maneras. Si se trata de un perro, el mouse no hace mucho más que evitar el camino del perro. Si es un gato, intenta esconderse. En tal situación, ¿está bien hacerlo? ¿Existe algún método mejor? – aps

    +2

    Puede tener múltiples métodos reactTo (...) en el objeto Mouse, uno para cada tipo de animal, y pasar el animal al que desea que reaccione el mouse. –

    0

    ¿Qué tal, en el caso de una fábrica de creación (consulte a continuación)? En este caso, no creo que sea apropiado que una subclase de Animal sepa cómo construir una jaula para sí misma. Parece estar fuera del alcance de lo que es un Animal y obliga a la subclase Animal a asumir comportamientos que no son intrínsecos a lo que es un 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(); 
    } 
    
    0

    Otro uso del funcionamiento de instaceOf podría ser el manejo de errores. Si usted tiene el control de errores similar para excepciones, y que desea tener todo en un solo lugar se puede usar:

    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...... 
        } 
    
    } 
    

    con el código de seguridad, se evita tener muchos

    } catch <Exception> { 
    

    bloques y en lugar de tener sólo una

    } catch (Throwable t) { 
        handleError(t, request); 
        return "errorPage" or whateveryouwant; 
    } 
    

    Además, es una cosa más, es revisar el código fuente de java, encontrará tantos usos de instaceof ..

    Y un buen enlace: article about usage of instaceof

    Cuestiones relacionadas