2009-11-02 18 views
5

Originalmente tenía un problema de diseño en el que necesitaba cinco subclases de una superclase, donde todas menos dos usarían el mismo método genérico de hacer las cosas y las otras dos necesitarían un manejo especial. Quería evitar escribir el método cinco veces; dos casos especiales y tres idénticos.¿Cómo llamar a métodos anulados en una subclase? Posible candidato para la refactorización

Así que todas las clases heredaban SuperClass y su método doSomething(), y tenían SubClassSpecial1 y SubClassSpecial2 que reemplazaban con su propio método doSomeThing.

Esto era todo muy bien hasta que escribí un método que parecía algo así como

void fooBar(SuperClass obj) { 
    obj.doSomething() 
} 

y que podría ser llamado como fooBar(new SubClassSpecial1());

El problema es que la clase en tiempo de ejecución de la variable obj es ahora la de su superclase, y por lo tanto llamará a los métodos definidos en la superclase. Por supuesto, podría hacer un método abstracto doSometing() en la superclase, y hacer que cada subclase implemente su propia versión, pero eso duplicaría el código en tres de las clases. Y quiero evitar hacer eso ...

que iba a perder cualquier ganancia polimorfismo da si tuviera una gran cantidad de ramificación a través

if(obj.getClass().getName() == "SubClassSpecial1") ((SubClassSpecial1) obj).doSomething()K; 
else if ... 

Entonces, ¿qué debo hacer con el fin de hacer el diseño más elegante y no-hackish?

+0

Este artículo debe al menos etiquetarse con el lenguaje de programación con el que está codificando. –

+0

fijo. agregué una etiqueta java Gracias. pero pensé que este era un problema de diseño general que iba más allá de las barreras del idioma. – oligofren

+0

¿Puede darnos los encuadres de sus definiciones de clase? –

Respuesta

2

Lo que ha descrito debería funcionar bien tal como está.

¿Está realmente obj.doSomething() llamando a la implementación de la superclase? Si es así, no lo está anulando adecuadamente. Verifique que no haya cambiado la firma en sus versiones anuladas.

+0

Bueno, se supone que no debe hacer eso? El tipo de tiempo de ejecución del objeto se declara como el de su superclase y, por lo tanto, debe llamar a la versión de la superclase. Si fuerzo ((SubClassSpecial1) obj) .doSomething() llamará a la versión subclasificada. ¿O están mis suposiciones erróneas aquí sobre cómo funcionan las clases de herencia y tiempo de ejecución? – oligofren

+0

Hmm ... Escribí un programa de prueba que muestra fallas en mis suposiciones sobre cómo funcionan los cambios en el tipo de tiempo de ejecución de un objeto. Necesito verificar esto antes de volver ... – oligofren

+2

Su suposición es incorrecta. No necesita lanzar obj a SubClassSpecial1 para obtener el método SubClassSpecial1 doSomething(), sucederá automáticamente. Eso es polimorfismo. Prueba algunas pruebas –

5

estoy un poco confundido por esta parte de su pregunta:

Por supuesto, lo que quería hacer era tener cada objeto llamar su propia versión de doSomething(), pero no se dio cuenta de que en Para hacer eso, obj necesitaba ser declarado como uno de los métodos subclasificados. Y ahora es un desastre.

Por supuesto, la declaración no importa, el método doSomething() siempre se invocará de acuerdo con el tipo de tiempo de ejecución de la clase.

Así que creo que lo que intentas hacer debería funcionar bien, p. estas declaraciones se pueden usar para pasar al método foobar:

SuperClass sc1 = new SubClassSpecial1(); 
SubClassSpecial2 sc2 = new SubClassSpecial2(); 
//etc.. 
+0

Bien, intentaré editar esa parte y reformularme. Lo que quería decir es que quería que el objeto llamara a su propio método (si se reemplaza), no el de su superclase. Y el problema es que, como está declarado (en la declaración del método) como una instancia de la superclase, su tipo de clase de tiempo de ejecución será el de su superclase y, por lo tanto, llamará al método de la superclase. Espero que esto tenga algún sentido ... – oligofren

+2

No se supone que esté un poco fuera de allí, la clase que utiliza al crear un nuevo objeto con la palabra clave 'nueva' determina el tipo de tiempo de ejecución de su objeto. Entonces, en mi ejemplo, la variable SuperClass sc1 contiene una referencia a un objeto cuyo tipo de tiempo de ejecución es SubClassSpecial1. Ahora esto puede ser un poco confuso, espero que lo entiendas :-) – NickDK

+0

Gracias, comencé a sospechar que algo estaba mal después de la respuesta de Terry y descubrí que Java no hizo lo que pensé que sería la manera "intuitiva" de hacerlo. escribiendo un código de prueba Todavía encuentro este comportamiento un poco extraño, pero al menos ahora sé :) – oligofren

1

Cuando se tiene esto:

void fooBar(SuperClass obj) { 
    obj.doSomething(); 
} 

entonces el en tiempo de compilación tipo de obj es SuperClass. Esto significa que el compilador comprobará que SuperClass tiene un método doSomething().
En tiempo de ejecución puede sustituir una subclase de SuperClass, este es el Liskov Substitution Principle.El método foobar() no sabe, y no debería saber, cuál es el tipo de tiempo de ejecución de obj, solo que deriva de SuperClass y así se puede llamar a doSomething().

En cuanto a su ejemplo:

fooBar(new SubClassSpecial1()); 

En este caso le toca a saber que el tiempo de ejecución tipo del parámetro es SubClassSpecial1 que anula específicamente doSomething(). En todos los casos, se llama al método correcto.

Una palabra sobre refactorización. Es posible que desee considerar refactorizar su jerarquía.
Su clase base SuperClass debe definir doSomething() como abstracto. Sus tres clases que necesitan la misma implementación de doSomething() deben heredarlo de una clase base intermedia que tenga esa implementación específica. Sus dos clases especiales deben heredar directamente desde SuperClass y tener su propia implementación de doSomething().

+0

¡Gracias, quamrama! Para mí, esta fue la más informativa de las respuestas, aunque mi principal queja ya fue respondida por otra persona. Me hizo entender mucho más sobre cómo funciona esto, y la sugerencia de refactorización es realmente útil. ¡Gran respuesta! – oligofren

Cuestiones relacionadas