El lenguaje es irrelevante cuando se trata de composición vs herencia. Si comprende qué clase es y qué instancia es de una clase, entonces tiene todo lo que necesita.
La composición es simplemente cuando una clase es compuesta por de otras clases; o para decirlo de otra manera, una instancia de un objeto tiene referencias a instancias de otros objetos.
Herencia es cuando una clase hereda métodos y propiedades de otra clase.
Digamos que tiene dos funciones, A y B. Desea definir una tercera funcionalidad, C, que tiene algunas o todas de A y B. Puede hacer que C se extienda desde B y A, en cuyo caso C tiene todo lo que B y A tienen porque C isA
B y A, o puede hacer que cada instancia de C tenga una instancia de A y una instancia de B, e invoque elementos en esas funcionalidades. En el último caso, cada instancia C en efecto envuelve una instancia de B y una instancia de A.
Por supuesto, dependiendo del idioma, es posible que no pueda tener una clase de 2 clases (por ejemplo, Java no es compatible con herencia múltiple), pero ese es un detalle específico del idioma que no tiene nada que ver con el concepto.
Ahora, para los detalles específicos del lenguaje ...
he utilizado la palabra clase, pero JavaScript no tiene noción de clase como tal. Tiene objetos, y eso es (aparte de los tipos simples). Javascript usa herencia prototípica, lo que significa que tiene una forma de definir eficientemente los objetos y los métodos en esos objetos (este es el tema para otra pregunta, puede buscar SO ya que hay respuestas)
Así que vamos con nuestro ejemplo anteriormente, que tiene a, B, y C.
Por herencia, que tendría
// define an object (which can be viewed as a "class")
function A(){}
// define some functionality
A.prototype.someMethod = function(){}
Si quería C para extender a, que haría
Ahora cada instancia de C tendría el método someMethod
, porque cada instancia de C "ISA" A.
Javascript no tiene herencia múltiple * (más sobre esto más adelante), por lo que no se puede tener C se extiende A y B. Sin embargo, puede usar la composición para darle la funcionalidad.De hecho, esta es una de las razones por las que la composición es preferida por algunos sobre la herencia; no hay límites para combinar la funcionalidad (pero esta no es la única razón).
function C(){
this.a = new A();
this.b = new B();
}
// someMethod on C invokes the someMethod on B.
C.someMethod = function(){
this.a.someMethod()
}
Así que hay ejemplos sencillos para la herencia y la composición. Sin embargo, este no es el final de la historia. Dije antes que el Javascript no es compatible con la herencia múltiple, y en cierto sentido no, porque no se puede basar el prototipo de un objeto en los prototipos de objetos múltiples; es decir, no se puede hacer
C.prototype = new B();
C.prototype.constructor = B;
C.prototype.constructor = A;
porque tan pronto como lo hace la tercera, línea, acaba de deshacer la segunda línea. Esto tiene implicaciones para el operador instanceof
.
Sin embargo, esto realmente no importa, porque simplemente porque no se puede redefinir el constructor de un objeto dos veces, todavía puede añadir cualquier método que desea el prototipo de un objeto. Así que sólo porque no se puede hacer el ejemplo anterior, todavía se puede añadir todo lo que quiere C.prototype, incluyendo todos los métodos en los prototipos de ambos
Muchos marcos A y B.
apoyar esto y hacerlo fácil. Hago mucho trabajo de Sproutcore; con dicho marco que puede hacer
A = {
method1: function(){}
}
B = {
method2: function(){}
}
C = SC.Object.extend(A, B, {
method3: function(){}
}
Aquí he definido funcionalidad en objetos literales A
y B
, y después se añadió la funcionalidad de ambos para C
, por lo que cada instancia de C tiene los métodos 1, 2 y 3. En este caso particular, el método extend
(proporcionado por el marco) hace todo el trabajo pesado de configurar los prototipos de los objetos.
EDITAR - En sus comentarios, saca una buena pregunta, es decir, "Si utiliza la composición, ¿cómo concilia el alcance del objeto principal con el alcance de los objetos de los que se compone el objeto principal".
Hay muchas maneras. El primero es simplemente pasar argumentos. Así que
C.someMethod = function(){
this.a.someMethod(arg1, arg2...);
}
Aquí no estás jugando con telescopios, simplemente estás pasando argumentos. Este es un enfoque simple y muy viable. (Los argumentos pueden venir de this
o ser aprobada en, lo que sea ...)
Otra manera de hacerlo sería utilizar los call
(o apply
) métodos de Javascript, que básicamente le permite establecer el alcance de una función.
C.someMethod = function(){
this.a.someMethod.call(this, arg1, arg2...);
}
a ser un poco más claro, lo siguiente es equivalente
C.someMethod = function(){
var someMethodOnA = this.a.someMethod;
someMethodOnA.call(this, arg1, arg2...);
}
en JavaScript, las funciones son objeto, por lo que puede asignarlos a variables.
la call
invocación aquí es establecer el alcance de someMethodOnA
a this
, que es la instancia de C.
La pregunta es demasiado vaga. Probablemente una mejor opción para [programmers.se] (http://programmers.stackexchange.com). –
Si es demasiado vago, IMO no es adecuado para ningún sitio. –
¿Cómo podría ser más específico? Presento código usando herencia, ahora estoy interesado en verlo construido usando composición. Hay otras preguntas que son iguales para otros idiomas. – Brian