2010-10-20 9 views

Respuesta

4

En Java, cada vez que hereda de una clase, su nueva clase también se convierte automáticamente en un subtipo del tipo de clase original. Como es un subtipo, debe adherirse al Liskov substitution principle.
Este principio básicamente dice que debe poder usar el subtipo en cualquier lugar donde se espere el supertipo. Esto limita severamente la forma en que el comportamiento de su nueva clase heredada puede diferir de la clase original.
Sin embargo, ningún compilador podrá obligarlo a cumplir este principio, pero puede tener problemas si no lo hace, especialmente cuando otros programadores utilizan sus clases.

En los idiomas que permiten subclases sin subtipificación (como el CZ language), la regla "Favorecer la composición del objeto sobre la herencia" no es tan importante como en lenguajes como Java o C#.

+0

>> Si estuviera programando en un lenguaje que permite la creación de subclases sin subtipar, ¿se refiere a la mayoría del lenguaje de scripting? – Howard

+2

Me gusta que el autor de la pregunta muestre que quería recibir la respuesta opuesta a lo que se le preguntó. Nos pidieron que proporcionáramos un ejemplo de contador, donde la herencia sería más apropiada. Sin embargo, debe darse por vencido y aceptar un ejemplo más donde la herencia apesta de nuevo. Esto es un misterio. OOP domina el mundo, sin embargo, su característica principal, la herencia, ¡nunca debe usarse a favor de una buena composición estructural antigua! ¿Podría ser que deberíamos preferir los condicionales sobre el polimorfismo también porque el polimorfismo se logra a través de la (mala) herencia en java? – Val

+1

Puede ser que Java también sea basura porque basándose en elementos como Integer se extiende Número y ByteInputStream extiende InputStream y cada objeto deriva métodos de bloqueo, hash e igualdad del Objeto. Obviamente, si heredar algo es malo, entonces Java está equivocado desde el principio. – Val

11

La herencia es apropiada para las relaciones is-a. No es adecuado para las relaciones has-a.

Como la mayoría de las relaciones entre las clases/componentes entran en la has-a cubo (por ejemplo, una clase Car no es probable que un HashMap, pero puede tener un HashMap), se sigue entonces la composición es a menudo una mejor idea de las relaciones de modelado entre clases en lugar de herencia.

Esto no significa que la herencia no sea útil o no sea la solución correcta para algunos escenarios.

7

Mi respuesta simple es que debe usar la herencia para behavioral propósitos. Las subclases deben anular los métodos para cambiar el comportamiento del método y del objeto en sí.

Este artículo (entrevista con Erich Gamma, uno de los GoF) explica claramente por qué Favor object composition over class inheritance.

0

Solo piensa que es como tener un "es-un" o un "tiene-un" relación

En este ejemplo Humano "es-un" animal, y puede hereda diferentes datos de la clase de Animal. Por lo tanto, se utiliza la herencia:

abstract class Animal { 
    private String name; 
    public String getName(){ 
     return name; 
    } 
    abstract int getLegCount(); 
} 

class Dog extends Animal{ 
    public int getLegCount(){ 
     return 4; 
    } 
} 

class Human extends Animal{ 
    public int getLegCount(){ 
     return 2; 
    } 
} 

La composición tiene sentido si un objeto es el propietario de otro objeto. Como un objeto humano que posee un objeto Dog. Así, en el siguiente ejemplo un objeto humano "tiene-un" objeto perro

class Dog{ 
    private String name; 
} 
class Human{ 
    private Dog pet; 
} 

esperanza de que ayudó ...

0

Es un principio fundamental del diseño de un buen OOD. Puede asignar un comportamiento a una clase dinámicamente "en tiempo de ejecución", si usa composición en su diseño en lugar de herencia, como en Patrón de estrategia. Decir,

interface Xable { 
doSomething(); 
} 

class Aable implements Xable { doSomething() { /* behave like A */ } } 
class Bable implements Xable { doSomething() { /* behave like B */ } } 

class Bar { 
Xable ability; 

public void setAbility(XAble a) { ability = a; } 

public void behave() { 
ability.doSomething(); 
} 

} 
/*now we can set our ability in runtime dynamicly */ 

/*somewhere in your code */ 

Bar bar = new Bar(); 
bar.setAbility(new Aable()); 
bar.behave(); /* behaves like A*/ 
bar.setAbility(new Bable()); 
bar.behave(); /* behaves like B*/ 

si se hizo uso de la herencia, el "bar" obtendría el comportamiento "staticly" sobre la herencia.

1

La herencia permite que un objeto del tipo derivado se use en casi cualquier circunstancia donde uno usaría un objeto del tipo base. La composición no permite esto. Utilice la herencia cuando se requiera dicha sustitución, y la composición cuando no sea así.

0

La herencia es necesaria para la subtipificación. Consideremos:

class Base { 
    void Foo() { /* ... */ } 
    void Bar() { /* ... */ } 
} 

class Composed { 
    void Foo() { mBase.Foo(); } 
    void Bar() { mBase.Foo(); } 
    private Base mBase; 
} 

Aunque Composed soporta todos los métodos de Foo no se puede pasar a una función que espera un valor de tipo Foo:

void TakeBase(Base b) { /* ... */ } 

TakeBase(new Composed()); // ERROR 

Por lo tanto, si desea polimorfismo, es necesario herencia (o su implementación de interfaz primo).

Cuestiones relacionadas