Estoy tratando de entender cómo se usa el polimorfismo en un proyecto de la vida real, pero solo puedo encontrar el ejemplo clásico (o algo similar) de tener una Animal
clase principal con un método speak()
, y muchas clases secundarias que anulan este método, y ahora Puede llamar al método speak()
en cualquiera de los objetos secundarios, por ejemplo:
Animal animal;
animal = dog;
animal.speak();
animal = cat;
animal.speak();
object-oriented
data-structures
polymorphism
Christopher
fuente
fuente
if(x is SomeType) DoSomething()
frecuencia, puede valer la pena usar polimorfismo. Para mí, el polimorfismo es una decisión similar a cuándo hacer un método separado, si descubro que repito el código varias veces, generalmente lo refactorizo en un método, y si descubro que estoy haciendoif object is this type do this
código a menudo, podría ser Vale la pena refactorizar y agregar una interfaz o clase.Respuestas:
Stream es un gran ejemplo de polimorfismo.
La secuencia representa una "secuencia de bytes que se pueden leer o escribir". Pero esta secuencia puede provenir de archivos, memoria o muchos tipos de conexiones de red. O puede servir como decorador, que envuelve la secuencia existente y transforma los bytes de alguna manera, como el cifrado o la compresión.
De esta manera, el cliente que usa Stream no necesita preocuparse de dónde provienen los bytes. Solo que se pueden leer en secuencia.
Algunos dirían que
Stream
es un ejemplo incorrecto de polimorfismo, porque define muchas "características" que sus implementadores no admiten, como la transmisión de red que solo permite leer o escribir, pero no ambas al mismo tiempo. O falta de búsqueda. Pero esa es solo una cuestión de complejidad, ya queStream
puede subdividirse en muchas partes que podrían implementarse de forma independiente.fuente
Stream
son mi ejemplo de polimorfismo favorito de todos los tiempos. Ya ni siquiera intento enseñarle a la gente que el modelo defectuoso de 'animal, mamífero y perro'Stream
hace un trabajo mejor.Un ejemplo típico relacionado con los juegos sería una clase base
Entity
, que proporciona miembros comunes comodraw()
oupdate()
.Para un ejemplo orientado a datos más puro, podría haber una clase base que
Serializable
proporcione un comúnsaveToStream()
yloadFromStream()
.fuente
Existen diferentes tipos de polimorfismo, el de interés suele ser el polimorfismo / despacho dinámico en tiempo de ejecución.
Una descripción de muy alto nivel del polimorfismo de tiempo de ejecución es que una llamada a un método hace cosas diferentes dependiendo del tipo de tiempo de ejecución de sus argumentos: el objeto mismo es responsable de resolver una llamada a un método. Esto permite una gran cantidad de flexibilidad.
Una de las formas más comunes de usar esta flexibilidad es para la inyección de dependencia , por ejemplo, para que pueda cambiar entre diferentes implementaciones o inyectar objetos simulados para realizar pruebas. Si sé de antemano que solo habrá un número limitado de opciones posibles, podría intentar codificarlas con condicionales, por ejemplo:
Esto hace que el código sea difícil de seguir. La alternativa es introducir una interfaz para esa operación y escribir una implementación normal y una implementación simulada de esa interfaz, e "inyectar" a la implementación deseada en tiempo de ejecución. "Inyección de dependencia" es un término complicado para "pasar el objeto correcto como argumento".
Como ejemplo del mundo real, actualmente estoy trabajando en un tipo de problema de aprendizaje automático. Tengo un algoritmo que requiere un modelo de predicción. Pero quiero probar diferentes algoritmos de aprendizaje automático. Entonces definí una interfaz. ¿Qué necesito de mi modelo de predicción? Dada alguna muestra de entrada, la predicción y sus errores:
Mi algoritmo toma una función de fábrica que entrena un modelo:
Ahora tengo varias implementaciones de la interfaz del modelo y puedo compararlas entre sí. Una de estas implementaciones en realidad toma otros dos modelos y los combina en un modelo impulsado. Entonces, gracias a esta interfaz:
Un caso de uso clásico del polimorfismo está en las GUI. En un marco GUI como Java AWT / Swing / ... hay diferentes componentes . La interfaz de componente / clase base describe acciones como pintar en la pantalla o reaccionar a los clics del mouse. Muchos componentes son contenedores que administran subcomponentes. ¿Cómo podría dibujarse tal contenedor?
Aquí, el contenedor no necesita conocer de antemano los tipos exactos de los subcomponentes; siempre que se ajusten a la
Component
interfaz, el contenedor simplemente puede llamar al polimórficopaint()
método . Esto me da la libertad de extender la jerarquía de clases AWT con nuevos componentes arbitrarios.Hay muchos problemas recurrentes a lo largo del desarrollo de software que se pueden resolver aplicando el polimorfismo como técnica. Estos pares recurrentes de problemas y soluciones se denominan patrones de diseño , y algunos de ellos se recopilan en el libro del mismo nombre. En los términos de ese libro, mi modelo de aprendizaje automático inyectado sería una estrategia que utilizo para "definir una familia de algoritmos, encapsular cada uno y hacerlos intercambiables". El ejemplo de Java-AWT donde un componente puede contener subcomponentes es un ejemplo de un compuesto .
Pero no todos los diseños necesitan usar polimorfismo (más allá de habilitar la inyección de dependencia para las pruebas unitarias, que es un caso de uso realmente bueno). La mayoría de los problemas son muy estáticos. Como consecuencia, las clases y los métodos a menudo no se usan para el polimorfismo, sino simplemente como espacios de nombres convenientes y para la sintaxis de llamada del método bonito. Por ejemplo, muchos desarrolladores prefieren llamadas a métodos como
account.getBalance()
sobre una llamada de función en gran medida equivalenteAccount_getBalance(account)
. Ese es un enfoque perfectamente bueno, es solo que muchas llamadas de "método" no tienen nada que ver con el polimorfismo.fuente
Usted ve mucha herencia y polimorfismo en la mayoría de los kits de herramientas de IU.
Por ejemplo, en el kit de herramientas de JavaFX UI,
Button
hereda deButtonBase
qué hereda deLabeled
qué hereda deControl
qué hereda deRegion
qué hereda deParent
qué hereda deNode
quién hereda deObject
. Muchas capas anulan algunos métodos de los anteriores.Cuando desee que aparezca ese botón en la pantalla, entonces lo agrega a un
Pane
, que puede aceptar cualquier cosa heredada deNode
niño. Pero, ¿cómo sabe un Panel qué hacer con un Botón cuando solo lo ve como un objeto Nodo genérico? Ese objeto podría ser cualquier cosa. El panel puede hacer eso porque el Botón redefine los métodos de Nodo con cualquier lógica específica de botón. El panel solo llama a los métodos definidos en Node y deja el resto al objeto mismo. Este es un ejemplo perfecto de polimorfismo aplicado.Los juegos de herramientas de UI tienen una importancia muy alta en el mundo real, haciéndolos útiles para enseñar por razones académicas y prácticas.
Sin embargo, los kits de herramientas de IU también tienen un inconveniente significativo: tienden a ser enormes . Cuando un ingeniero de software neófito intenta comprender el funcionamiento interno de un marco de interfaz de usuario común, a menudo se encuentra con más de cien clases , la mayoría de ellas con fines muy esotéricos. "¿Qué diablos es un
ReadOnlyJavaBeanLongPropertyBuilder
? ¿Es importante? ¿Tengo tengo que entender lo que es bueno para?" Los principiantes pueden perderse fácilmente en esa madriguera de conejo. Por lo tanto, pueden huir aterrorizados o quedarse en la superficie donde simplemente aprenden la sintaxis y tratan de no pensar demasiado en lo que realmente está sucediendo bajo el capó.fuente
Aunque ya hay buenos ejemplos aquí, otro es reemplazar animales con dispositivos:
Device
puede serpowerOn()
,powerOff()
,setSleep()
y la latagetSerialNumber()
.SensorDevice
puede hacer todo esto, y proporcionar funciones polimórficas, tales comogetMeasuredDimension()
,getMeasure()
,alertAt(threashhold)
yautoTest()
.getMeasure()
no se implementará de la misma manera para un sensor de temperatura, un detector de luz, un detector de sonido o un sensor volumétrico. Y, por supuesto, cada uno de estos sensores más especializados puede tener algunas funciones adicionales disponibles.fuente
La presentación es una aplicación muy común, quizás la más común sea ToString (). Que es básicamente Animal.Speak (): le dices a un objeto que se manifieste.
En términos más generales, le dices a un objeto que "haga lo suyo". Piense en Guardar, Cargar, Inicializar, Eliminar, ProcessData, GetStatus.
fuente
Mi primer uso práctico del polimorfismo fue una implementación de Heap en Java.
Tuve una clase base con implementación de métodos insert, removeTop, donde la diferencia entre Heap max y min solo sería cómo funciona la comparación de métodos.
Entonces, cuando quería tener MaxHeap y MinHeap, podía usar la herencia.
fuente
Aquí hay un escenario de la vida real para el polimorfismo de la tabla de base de datos / aplicación web :
Utilizo Ruby on Rails para desarrollar aplicaciones web, y una cosa que muchos de mis proyectos tienen en común es la capacidad de cargar archivos (fotos, PDF, etc.). Entonces, por ejemplo, un
User
puede tener múltiples imágenes de perfil, yProduct
también puede tener muchas imágenes de productos. Ambos tienen el comportamiento de la carga y el almacenamiento de imágenes, así como el cambio de tamaño, la generación de imágenes en miniatura, etc. Con el fin de mantenerse seco y compartir el comportamiento dePicture
, queremos hacerPicture
de modo polimórfico que puede pertenecer a ambosUser
yProduct
.En Rails diseñaría mis modelos como tales:
y una migración de base de datos para crear la
pictures
tabla:Las columnas
imageable_id
yimageable_type
son utilizadas por Rails internamente. Básicamente,imageable_type
mantiene el nombre de la clase ("User"
,"Product"
, etc.), yimageable_id
es el ID del registro asociado. Entonces,imageable_type = "User"
yimageable_id = 1
sería el registro en lausers
tabla conid = 1
.Esto nos permite hacer cosas como
user.pictures
acceder a las imágenes del usuario, así comoproduct.pictures
obtener las imágenes de un producto. Luego, todo el comportamiento relacionado con la imagen se encapsula en laPhoto
clase (y no en una clase separada para cada modelo que necesita fotos), por lo que las cosas se mantienen SECAS.Más lecturas: Rails asociaciones polimórficas .
fuente
Hay muchos algoritmos de clasificación disponibles, como clasificación de burbujas, clasificación de inserción, clasificación rápida, clasificación de montón, etc.
El cliente proporcionado con la interfaz de clasificación solo se preocupa por proporcionar la matriz como entrada y luego recibe la matriz ordenada. Durante el tiempo de ejecución, dependiendo de ciertos factores, se puede usar la implementación de clasificación adecuada. Este es uno de los ejemplos del mundo real de dónde se usa el polimorfismo.
Lo que describí anteriormente es un ejemplo de polimorfismo en tiempo de ejecución, mientras que la sobrecarga de métodos es un ejemplo de polimorfosis en tiempo de compilación donde el cumplimiento depende de los tipos de parámetros i / p y o / p y el número de parámetros vincula al llamador con el método correcto en el tiempo de compilación en sí.
Espero que esto aclare.
fuente