¿Reemplazo por ejemplo de Java?

10

Así que soy bastante nuevo en la programación en el mundo real (fuera de los proyectos académicos) y he encontrado muchas publicaciones que dicen que usar instanceofes algo malo para determinar qué clase es un objeto específico.

Mi situación es que tengo tres clases, una clase de producto base, una que se extiende fuera de eso y otra que se extiende fuera de eso. Todos estos se almacenan en la misma tabla en una base de datos y tengo un código que necesita usar los métodos en cada uno para extraer datos de ellos.

¿Cuál es la mejor práctica para evitar esta forma de hacerlo? He leído algunas cosas sobre el polimorfismo, pero no puedo encontrar ningún ejemplo que solucione el problema que tengo. Por lo general, todos anulan un método que para mí no funcionará, ya que necesito extraer diferentes cosas de los diferentes objetos.

¿Hay una mejor manera de hacer esto o estoy atascado con el uso instanceofo algún tipo de reflexión para obtener los campos específicos de los objetos?

Thomas Mitchell
fuente
10
No es que la palabra clave instanceofesté mal; Tratar de encontrar la clase de un objeto suele ser el problema. No siempre está mal, pero probablemente lo sea en tu caso. Tal vez si nos dice lo que está tratando de lograr, podemos sugerirle una solución con polimorfismo.
Andres F.
2
De acuerdo, cada clase tiene datos específicos. Quiero extraer los datos específicos de estos. Creo que me he dado cuenta de la respuesta con la ayuda que he tenido. Algo así como un método llamado getSpecifics()que se implementa de manera diferente en cada uno, y cada uno devuelve los datos específicos de la clase.
Thomas Mitchell

Respuestas:

16

La razón que instanceofse desaconseja es que no es POO.

No debería haber ninguna razón para que el llamante / usuario de un objeto sepa de qué clase concreta es una instancia más allá de qué tipo de variable se declara como variable.

Si necesita un comportamiento diferente en las subclases, agregue un método e impleméntelos de manera diferente.

monstruo de trinquete
fuente
1
Entonces, un método getSpecifics()(o algo similar) en cada clase que devolverá los detalles para cada clase. ¿Es este el mejor enfoque?
Thomas Mitchell
@Schmooo Realmente necesita pensar dónde existe la funcionalidad común dentro del árbol de clases y qué contratos existen en cada nivel.
3
Pero, ¿qué pasa con un caso en que su objeto cruza capas y se pierde la información de tipo? Ejemplo creo a List. Lo paso a un objeto que tome cualquiera Iterable. Ahora ese segundo objeto lo pasa a un tercer objeto que toma una Listoptimización, o una Iterablepero es mucho más lento. El segundo no debería saber que es una lista, pero al tercero le gustaría saberlo. ¿No debería comprobar el tercer objeto, por ejemplo, para ver si puede aplicar la optimización? Ver, por ejemplo, guayaba FluentIterableque hace exactamente eso.
Laurent Bourgault-Roy
1
Yo diría que no siempre es el caso de que tenga que agregar el método a la clase. Por ejemplo, algunos códigos obtienen una excepción y se supone que deben hacer algo con ellos dependiendo de su tipo. Digamos, hace un informe o hace algo para recuperarse del error. Este tipo de funcionalidad definitivamente no se adapta a las excepciones. O, si las clases provienen de alguna biblioteca externa, entonces ni siquiera tiene los medios para modificar estas clases. En este caso, creo que es absolutamente válido confiar en el instanceof.
Malcolm
9

instanceof no es necesariamente algo malo, sin embargo, es algo que uno debe mirar.

Un ejemplo de dónde funciona correctamente es en un lugar donde se obtiene una colección del tipo base y solo se desean los de un subtipo. Obtener las direcciones de red NetworkInterface.getNetworkInterfaces()devuelve los objetos NetworkInterface que tienen una colección de objetos InetAddress, algunos de los cuales son Inet4Address y otros son Inet6Address. Si se quiere filtrar la colección de objetos Inet4Address, es necesario usar instanceof.

En la situación que se describe en la publicación original, hay una clase Base, algo que extiende esa clase base y algo que extiende la clase extendida. Si bien no es completamente informativo, parece tener las bases de un diseño menos que ideal.

Cuando devuelve una clase base, a menos que haya una buena razón para que se diseñe de esa manera (compatibilidad hacia atrás entre las especificaciones de una versión anterior), no debería intentar echar un vistazo a los tipos subyacentes. Si le devuelven un conjunto, sabe que está obteniendo un conjunto. Le permite al desarrollador cambiar más tarde de opinión para devolver un tipo más específico (SortedSet) o cambiar el tipo subyacente (HashSet a TreeSet) sin romper nada.

Reconsidere su diseño de cómo los objetos están estructurados y parentales para ver si uno puede hacer un mejor modelo de clase que no requiera una distinción de tipos.


fuente
Es posible que hacer que la interfaz especifique un isOfType(SomeEnum.IPv4)método podría ser una mejor manera de filtrar esas cualidades que inspeccionar el tipo de concreto instanceof. ¿Qué sucede si desea dividir su clase de implementación de IPv4 más tarde? No es que esto siempre sea mejor, pero es una consideración.
Steven Schlansker
@StevenSchlansker Eso podría funcionar para esa clase específica. Pero, ¿qué pasaría si uno necesitara inspeccionar el tipo concreto para ver si un lanzamiento es posible (o uno solo lanzaría y capturaría la excepción?) Inet6Address implementa más métodos que InetAddress. Le resultaría difícil trabajar con interfaces (¿una enumeración que enumera todas las clases del paquete o el cargador de clases?) Y eso significaría que el método debería implementarse manualmente (o algún código de reflexión en Object). Considera cómo hacerlo (o instanceof Serializable) || (o instanceof Externalizable). instanceof es mejor que la alternativa
1

Puede usar el método getClass ().

¿Estás seguro de que necesitas tres clases diferentes? ¿Tal vez una clase con un interruptor adentro servirá mejor?

Gangnus
fuente
77
getClassy instanceofcompartir desventajas. El polimorfismo es mejor que ambos cuando encaja, y no veo que no se ajuste al caso de uso de OP.
No tengo nada en contra de tu primera oración. Pero el segundo, lo siento, no puedo entender a qué te refieres en absoluto.
Gangnus
1
Con getClasspuedo todavía no compartir el mismo problema que el uso instanceof? Todavía tendré que averiguar cuál tengo y luego llamar a un conjunto de funciones. Idealmente, quiero un método que devuelva los datos específicos de esa clase sin necesidad de convertir a ese objeto.
Thomas Mitchell
Me estoy quejando de que ignoras el polimorfismo, ya que a menudo es una mejor opción. Estoy bastante seguro de que el caso de uso en la pregunta se puede hacer con polimorfismo, por lo que tampoco veo la necesidad de usarlo. (Aparte de eso, solo reproducir la respuesta de otra persona no es bueno).
2
@Gangus No pienso en esto como un "ataque", no quiero ofenderte. Pero lo que sea. No, la pregunta no es "qué más se puede usar", es "¿hay una mejor manera de hacer esto?". A menos que desee argumentar que getClasses una mejor manera de hacerlo, no tiene nada que ocupar la mayor parte de una respuesta ;-)
1

Por lo general, cuando me encuentro con ganas de saber el tipo de algo, significa que implementé mal la estructura de mi objeto. La mayoría de estas veces se trata de violar el LSP .

Sin embargo, hay momentos en los que desearía tener una forma de hacer un despacho dinámico y ahorrar una tonelada de código de placa de caldera y proteger mi estructura de objetos en el futuro. C # proporciona la palabra clave dinámica en las entregas más recientes del marco, pero que yo sepa, Java todavía no tiene algo similar.

Dicho esto, instanceof es generalmente mejor que comparar clases, ya que admitirá la herencia correctamente. También puede usar métodos como isAssignableFrom y otros de la API reflexion. Si desea implementar algo como el despacho dinámico, puede hacerlo a través de la API de reflexión, pero tenga cuidado, será lento. Úselo con precaución, idealmente debe corregir la estructura de objetos y el diseño de su aplicación si puede.

Espero que esto ayude

Newtopian
fuente