language-agnostic - example - polymorphism python
Intenta describir el polimorfismo tan fácil como puedas (24)
Cada lata con una tapa simple se abre de la misma manera.
Como ser humano, sabes que puedes Abrir () cualquier cosa que puedas encontrar.
Cuando se abre, no todas las latas se comportan de la misma manera.
Algunos contienen nueces, algunos contienen serpientes falsas que salen.
El resultado depende de qué tipo de lata, si la lata era un "CanOfNuts" o un "CanOfSnakes", pero esto no tiene ninguna incidencia en CÓMO lo abre. Simplemente sabe que puede abrir cualquier Can, y obtendrá algún tipo de resultado que se decide según el tipo de Can que abrió.
pUnlabledCan-> Open (); // podría dar nueces, podría dar serpientes. No lo sabemos hasta que lo llamemos
Open () tiene un tipo de devolución genérico de "Contenido" (o podemos decidir que no hay tipo de devolución), de modo que abrir siempre tiene la misma firma de función.
Tú, el humano, eres el usuario / llamante.
Open () es la función virtual / polimórfica.
"Can" es la clase base abstracta.
CanOfNuts y CanOfSnakes son los hijos polimórficos de la clase "Can".
Cada Can se puede abrir, pero lo que específicamente hace y qué tye específico de contenidos devuelve se define por qué tipo de cosas puede ser.
Todo lo que sabes cuando ves pUnlabledCan es que puedes Abrirlo (), y devolverá los contenidos. Cualquier otro comportamiento (como reventar serpientes en su cara) se decide por la Can específica.
¿Cómo se puede describir el polimorfismo de una manera fácil de entender?
Podemos encontrar mucha información sobre el tema en internet y libros, como en el tipo de polimorfismo . Pero intentemos hacerlo lo más simple posible.
Dos objetos responden al mismo mensaje con diferentes comportamientos; el remitente no tiene que importarle.
El actor vs. el personaje (o rol)
El polimorfismo consiste en dividir el mundo en cuadros en función de las propiedades comunes y tratar los elementos en un cuadro dado como intercambiables cuando solo desee utilizar estas propiedades comunes.
El polimorfismo es el almacenamiento de valores de más de un tipo en una ubicación de un solo tipo.
Tenga en cuenta que la mayoría de las otras respuestas a esta pregunta, en el momento de escribir estas líneas, en realidad describen el despacho dinámico, no el polimorfismo.
en.wikipedia.org/wiki/Dynamic_dispatch requiere polimorfismo, pero lo contrario no es cierto. Uno podría imaginar un lenguaje muy similar a Java o C # pero cuyo System.Object no tenía miembros; Encasillado sería necesario antes de hacer cualquier cosa con el valor. En este lenguaje nocional, habría polimorfismo, pero no necesariamente métodos virtuales, o cualquier otro mecanismo dinámico de despacho.
El despacho dinámico es el concepto relacionado pero distinto, suficientemente descrito en la mayoría de las otras respuestas. Sin embargo, la forma en que normalmente funciona en los lenguajes orientados a objetos (seleccionar una función basada en el primer tipo de argumento ("este" o "propio")) no es la única forma en que puede funcionar. El envío múltiple también es posible, donde la selección se aplica a todos los tipos de todos los argumentos.
De manera similar, la resolución de sobrecarga y el despacho múltiple son análogos exactos entre sí; la resolución de sobrecarga es despacho múltiple aplicado a tipos estáticos, mientras que el despacho múltiple es la resolución de sobrecarga aplicada a los tipos de tiempo de ejecución almacenados en ubicaciones polimórficas.
El polimorfismo es la capacidad de tratar diferentes cosas como si fueran lo mismo al establecer una identidad compartida entre ellos y luego explotarla.
El polimorfismo es la solución orientada a objetos para el problema de pasar una función a otra función. En C puedes hacer
void h() { float x=3.0; printf("%f", x); }
void k() { int y=5; printf("%i", y); }
void g(void (*f)()) { f(); }
g(h); // output 3.0
g(k); // output 5
En C, las cosas se complican si la función depende de parámetros adicionales. Si las funciones hyk dependen de diferentes tipos de parámetros, usted tiene problemas y debe usar casting. Debe almacenar esos parámetros en una estructura de datos y pasar un puntero a esa estructura de datos a g, que lo pasa a h o k. hyk convierten el puntero en un puntero a la estructura adecuada y descomprimen los datos. Muy desordenado y muy inseguro debido a posibles errores de lanzamiento:
void h(void *a) { float* x=(float*)a; printf("%f",*x); }
void k(void *a) { int* y=(int*)a; printf("%i",*y); }
void g(void (*f)(void *a),void *a) { f(a); }
float x=3.0;
int y=5;
g(h,&x); // output x
g(k,&y); // output y
Entonces inventaron el polimorfismo. hyk son promovidos a clases y las funciones reales a métodos, los parámetros son variables miembro de la clase respectiva, h o k. En lugar de pasar la función, pasa una instancia de la clase que contiene la función que desea. La instancia contiene sus propios parámetros.
class Base { virtual public void call()=0; }
class H : public Base { float x; public void call() { printf("%f",x);} } h;
class K : public Base { int y; public void call() { printf("%i",y);} } k;
void g(Base &f) { f.call(); };
h.x=3.0;
k.y=5;
g(h); // output h.x
g(k); // output k.x
El polimorfismo es lo que obtienes cuando el mismo método se aplica a múltiples clases. Por ejemplo, tanto una cadena como una lista pueden tener métodos de "inversión". Ambos métodos tienen el mismo nombre ("Reverse"). Ambos métodos hacen algo muy similar (invierten todos los caracteres o invierten el orden de los elementos en la lista). Pero la implementación de cada método "Reverse" es diferente y específica para su clase. (En otras palabras, la cadena se invierte como una cadena y la lista se invierte como una lista).
Para usar una metáfora, podría decir "Hacer la cena" a un chef francés o a un chef japonés. Cada uno realizaría "hacer la cena" a su manera característica.
El resultado práctico es que puede crear un "Motor de inversión" que acepte un objeto y llame "Inverso" sobre él. Siempre que el objeto tenga un método Reverse, su Reversing Engine funcionará.
Para extender la analogía del chef, podrías construir un "Waiterbot" que les diga a los chefs que "hagan la cena". El Waiterbot no tiene que saber qué tipo de cena se va a hacer. Ni siquiera tiene que asegurarse de que está hablando con un chef. Lo único que importa es que el "chef" (o bombero, máquina expendedora o dispensador de comida para mascotas) sepa qué hacer cuando se le diga "Haga la cena".
Lo que esto le compra como programador es menos líneas de código y seguridad de tipo o vinculación tardía. Por ejemplo, he aquí un ejemplo con seguridad de tipo y enlace anticipado (en un lenguaje c-like que estoy inventando a medida que avanzo):
class BankAccount {
void SubtractMonthlyFee
}
class CheckingAccount : BankAccount {}
class SavingsAccount : BankAccount {}
AssessFee(BankAccount acct) {
// This will work for any class derived from
// BankAccount; even classes that don''t exist yet
acct.SubtractMonthlyFee
}
main() {
CheckingAccount chkAcct;
SavingsAccount saveAcct;
// both lines will compile, because both accounts
// derive from "BankAccount". If you try to pass in
// an object that doesn''t, it won''t compile, EVEN
// if the object has a "SubtractMonthlyFee" method.
AssessFee(chkAcct);
AssessFee(saveAcct);
}
Aquí hay un ejemplo sin seguridad de tipo pero con enlace tardío:
class DatabaseConnection {
void ReleaseResources
}
class FileHandle {
void ReleaseResources
}
FreeMemory(Object obj) {
// This will work for any class that has a
// "ReleaseResources" method (assuming all
// classes are ultimately derived from Object.
obj.ReleaseResources
}
main() {
DatabaseConnection dbConn;
FileHandle fh;
// You can pass in anything at all and it will
// compile just fine. But if you pass in an
// object that doesn''t have a "ReleaseResources"
// method you''ll get a run-time error.
FreeMemory(dbConn);
FreeMemory(fh);
FreeMemory(acct); //FAIL! (but not until run-time)
}
Para un excelente ejemplo, mire el método .NET ToString (). Todas las clases lo tienen porque todas las clases se derivan de la clase Object. Pero cada clase puede implementar ToString () de una manera que tenga sentido para sí misma.
EDITAR: simple! = Corto, en mi humilde opinión
El polimorfismo es tratar las cosas de manera abstracta al confiar en el conocimiento de un "padre" común (piense en jerarquías como Animal como padre de perros y gatos).
Por ejemplo, todos los animales pueden respirar oxígeno, y si bien pueden hacer esto de manera diferente, se podría diseñar una instalación que proporcione oxígeno para que los animales respiren, lo que respalda tanto a los perros como a los gatos.
Como un poco más, puedes hacer esto a pesar de que Animal es un identificador "abstracto" (no hay nada "Animal" real, solo tipos de Animales).
El término polimorfismo también se puede aplicar a funciones de sobrecarga. Por ejemplo,
string MyFunc(ClassA anA);
string MyFunc(ClassB aB);
es un ejemplo de polimorfismo no orientado a objetos.
Es la capacidad que tienen los objetos para responder al mismo mensaje de diferentes maneras.
Por ejemplo, en idiomas como smalltalk, Ruby, Objective-C, solo tienes que enviar el mensaje y ellos responderán.
dao = XmlDao.createNewInstance() #obj 1
dao.save( data )
dao = RdbDao.createNewnewInstance() #obj 2
dao.save( data )
En este ejemplo, dos objetos diferentes respondieron de diferentes maneras a los mismos mensajes: "createNewInstance () and save (obj)"
Actúan de diferentes maneras, al mismo mensaje. En los idiomas anteriores, las clases pueden no estar en la misma jerarquía de clases, es suficiente que respondan al mensaje.
En lenguajes como Java, C ++, C # etc. Para asignar el objeto a una referencia de objeto, deben compartir la misma jerarquía de tipo implementando la interfaz o siendo una subclase de una clase común.
fácil ... y simple.
El polimorfismo es, por mucho, la característica más importante y relevante de la programación orientada a objetos.
Es solo una manera de hacer frío para llamar a un nuevo código. Usted escribe alguna aplicación que acepta alguna interfaz de "Forma" con métodos que otros deben implementar (ejemplo - getArea). Si a alguien se le ocurre una nueva forma de implementar esa interfaz, su código anterior puede llamar a ese nuevo código a través del método getArea.
Es una forma de tratar diferentes cosas que pueden hacer algo similar de la misma manera sin importar cómo lo hacen.
Supongamos que tiene un juego con varios tipos diferentes de vehículos circulando, como automóvil, camión, monopatín, avión, etc. Todos pueden detenerse, pero cada vehículo se detiene de una manera diferente. Algunos vehículos pueden necesitar cambiar de marcha y algunos pueden detenerse en seco. El polimorfismo te permite hacer esto
foreach (Vehicle v in Game.Vehicles)
{
v.Stop();
}
La forma en que se implementa la detención se difiere a los diferentes vehículos para que su programa no tenga que preocuparse por ello.
Esto es de mi answer de una pregunta similar. Aquí hay un ejemplo de polimorfismo en pseudo-C # / Java:
class Animal
{
abstract string MakeNoise ();
}
class Cat : Animal {
string MakeNoise () {
return "Meow";
}
}
class Dog : Animal {
string MakeNoise () {
return "Bark";
}
}
Main () {
Animal animal = Zoo.GetAnimal ();
Console.WriteLine (animal.MakeNoise ());
}
El método Main () no conoce el tipo de animal y depende del comportamiento de una implementación particular del método MakeNoise ().
La capacidad de un objeto de algún tipo (por ejemplo, un automóvil) para actuar (por ejemplo, freno) como uno de otro tipo (por ejemplo, un vehículo) que generalmente sugiere ascendencia común (por ejemplo, automóvil es un subtipo de vehículo) en un punto de la jerarquía de tipos .
La descripción más simple del polimorfismo es que es una forma de reducir declaraciones if / switch .
También tiene el beneficio de permitirle extender sus declaraciones if / switch (u otras) sin modificar las clases existentes.
Por ejemplo, considere la clase Stream
en .NET. Sin polimorfismo sería una sola clase masiva en la que cada método implementa una declaración de cambio algo así como:
public class Stream
{
public int Read(byte[] buffer, int offset, int count)
{
if (this.mode == "file")
{
// behave like a file stream
}
else if (this.mode == "network")
{
// behave like a network stream
}
else // etc.
}
}
En su lugar, permitimos que el tiempo de ejecución nos haga el cambio de una manera más eficiente, al elegir automáticamente la implementación en función del tipo concreto ( FileStream
, NetworkStream
), por ejemplo
public class FileStream : Stream
{
public override int Read(byte[] buffer, int offset, int count)
{
// behave like a file stream
}
}
public class NetworkStream : Stream
{
public override int Read(byte[] buffer, int offset, int count)
{
// behave like a network stream
}
}
La forma en que lo intento y pienso es algo que se ve igual pero puede tener diferentes funcionalidades dependiendo de la instancia. Entonces puedes tener un tipo
interface IJobLoader
pero dependiendo de cómo se use puede tener diferentes funcionalidades sin dejar de tener el mismo aspecto. Puede tener instancias para BatchJobLoader, NightlyJobLoader, etc.
Quizás estoy muy lejos.
La forma más simple de describirlo: un verbo que se puede aplicar a más de un tipo de objeto.
Todo lo demás, como dijo Hillel, es solo comentario.
Las manzanas y las naranjas son ambas frutas. La fruta se puede comer. Por lo tanto, se pueden comer manzanas y naranjas.
¿El pateador? ¡Los comes de manera diferente! Pelas las naranjas, pero no las manzanas.
Entonces, la implementación es diferente, pero el resultado final es el mismo, se come la fruta .
Misma sintaxis, diferente semántica.
Poli: muchos
Morfismo: formas / formas
Si camina como un pato y grazna como un pato, entonces puedes tratarlo como un pato en cualquier lugar donde necesites un pato.
Este es un mejor artículo en realidad
El polimorfismo permite a los Objetos "mirar" lo mismo, pero se comporta de diferentes maneras. El ejemplo habitual es tomar una clase base animal con un Método Speak (), una subclase dog emitiría una Corteza mientras que una subclase Pig emitiría un oink.
La respuesta corta de 5 segundos que la mayoría de la gente utiliza para que otros desarrolladores puedan entenderse. El polimorfismo es una sobrecarga y una anulación
El polimorfismo es la funcionalidad del lenguaje que permite que el código algorítmico de alto nivel opere sin cambios en múltiples tipos de datos.
Esto se hace asegurando que las operaciones invoquen la implementación correcta para cada tipo de datos. Incluso en un contexto de OOP (según la etiqueta de esta pregunta), esta "implementación correcta" puede resolverse en tiempo de compilación o en tiempo de ejecución (si su idioma es compatible con ambas). En algunos lenguajes como C ++, el soporte proporcionado por el compilador para el polimorfismo en tiempo de ejecución (es decir, despacho virtual) es específico de OOP, mientras que otros tipos de polimorfismo también pueden operar en tipos de datos que no son objetos (es decir, no instancias struct
o class
, pueden ser tipos integrados como int
o double
).
(Los tipos de polimorfismo que C ++ admite se enumeran y contrastan en mi respuesta: Polimorfismo en c ++ : incluso si programa otros idiomas, es potencialmente instructivo)