La herencia, el polimorfismo y la encapsulación son las tres características más distintas e importantes de la POO, y de ellas, la herencia tiene una alta estadística de uso en estos días. Estoy aprendiendo JavaScript, y aquí, todos dicen que tiene herencia prototípica, y la gente en todas partes dice que es algo muy diferente de la herencia clásica.
Sin embargo, no puedo entender cuál es su diferencia desde el punto de vista práctico. En otras palabras, cuando define una clase base (prototipo) y luego deriva algunas subclases de ella, ambos tienen acceso a funcionalidades de su clase base, y pueden aumentar las funciones en las clases derivadas. Si consideramos que lo que dije es el resultado previsto de la herencia, ¿por qué debería importarnos si estamos usando una versión prototípica o clásica?
Para aclararme más, no veo diferencia en la utilidad y los patrones de uso de la herencia prototípica y clásica. Esto hace que no me interese saber por qué son diferentes, ya que ambos resultan en lo mismo, OOAD. ¿Cuán prácticamente (no teóricamente) la herencia prototípica es diferente de la herencia clásica?
fuente
La herencia clásica hereda el comportamiento, sin ningún estado, de la clase padre. Hereda el comportamiento en el momento en que se instancia el objeto.
La herencia de prototipos hereda el comportamiento y el estado del objeto padre. Hereda el comportamiento y el estado en el momento en que se llama al objeto. Cuando el objeto primario cambia en tiempo de ejecución, el estado y el comportamiento de los objetos secundarios se ven afectados.
La "ventaja" de la herencia prototípica es que puede "parchear" el estado y el comportamiento después de que se hayan instanciado todos sus objetos. Por ejemplo, en el marco Ext JS es común cargar "anulaciones" que parchean los componentes principales del marco una vez que se ha instanciado el marco.
fuente
class C(object): def m(self, x): return x*2
y luegoinstance = C()
cuando corroinstance.m(3)
me sale6
. Pero si luego cambioC
asíC.m = lambda s, x: x*x
y corroinstance.m(3)
ahora obtengo9
. Lo mismo ocurre si hago unclass D(C)
y cambio un método enC
cualquier instancia deD
recibir el método cambiado también. ¿Estoy malinterpretando o esto significa que Python no tiene herencia clásica según su definición?Primero: la mayoría de las veces, usarás objetos, no los definirás, y usar objetos es lo mismo bajo ambos paradigmas.
Segundo: la mayoría de los entornos prototípicos utilizan el mismo tipo de división que los entornos basados en clases: datos mutables en la instancia, con métodos heredados. Entonces hay muy poca diferencia de nuevo. (Véase mi respuesta a esta pregunta desbordamiento de pila , y el mismo papel la organización de programas sin clases . Mira Citeseer para una versión PDF .)
Tercero: la naturaleza dinámica de Javascript tiene una influencia mucho mayor que el tipo de herencia. El hecho de que pueda agregar un nuevo método a todas las instancias de un tipo asignándolo al objeto base es claro, pero puedo hacer lo mismo en Ruby, reabriendo la clase.
Cuarto: las diferencias prácticas son pequeñas, mientras que la cuestión práctica de olvidarse del uso
new
es mucho mayor, es decir, es mucho más probable que se vea afectado por la falta de unnew
código que por la diferencia entre el código prototípico y el clásico. .Dicho todo esto, la diferencia práctica entre la herencia prototípica y la clásica es que sus métodos (clases) de cosas que mantienen son los mismos que sus datos (instancias) de cosas que mantienen. Esto significa que puede desarrollar sus clases poco a poco, usando las mismas herramientas de manipulación de objetos que usarías en cualquier instancia. (De hecho, así es como lo hacen todas las bibliotecas de emulación de clase. Para un enfoque que no sea como todos los demás, mira Traits.js ). Esto es principalmente interesante si está realizando una metaprogramación.
fuente
La herencia de prototipos en JavaScript es diferente de las clases en estas formas importantes:
Los constructores son simplemente funciones que puede llamar sin
new
:No hay variables o métodos privados, en el mejor de los casos puede hacer esto:
En el ejemplo anterior, no puede extender la clase de manera significativa si se recurre a variables y métodos privados falsos y, además, cualquier método público que haya declarado se volverá a crear cada vez que se cree una nueva instancia.
fuente
color
,r
,x
,y
ydrawCircle
que están vinculados con el ámbito del léxicoCircle
Circle.call()
como constructor? Parece que estás tratando de describir "objetos funcionales" (un nombre inapropiado ...)