simple - relación de composición java
Diferencia entre herencia y composición (17)
¿Son la composición y la herencia lo mismo? Si quiero implementar el patrón de composición, ¿cómo puedo hacer eso en Java?
¿Son la composición y la herencia lo mismo?
Ellos no son lo mismo.
Composition : permite tratar a un grupo de objetos de la misma manera que una instancia única de un objeto. La intención de un compuesto es "componer" objetos en estructuras de árbol para representar jerarquías de parte-todo
Inheritance : una clase hereda campos y métodos de todas sus superclases, ya sean directas o indirectas. Una subclase puede anular los métodos que hereda, o puede ocultar campos o métodos que hereda.
Si quiero implementar el patrón de composición, ¿cómo puedo hacer eso en Java?
Artículo de Composition es lo suficientemente bueno para implementar el patrón compuesto en Java.
Participantes clave:
Componente :
- Es la abstracción para todos los componentes, incluidos los compuestos
- Declara la interfaz para objetos en la composición
Hoja :
- Representa objetos de hoja en la composición
- Implementa todos los métodos de componentes
Compuesto :
- Representa un Componente compuesto (componente que tiene hijos)
- Implementa métodos para manipular niños
- Implementa todos los métodos de Componente, generalmente delegándolos a sus hijos
Ejemplo de código para comprender el patrón compuesto :
import java.util.List;
import java.util.ArrayList;
interface Part{
public double getPrice();
public String getName();
}
class Engine implements Part{
String name;
double price;
public Engine(String name,double price){
this.name = name;
this.price = price;
}
public double getPrice(){
return price;
}
public String getName(){
return name;
}
}
class Trunk implements Part{
String name;
double price;
public Trunk(String name,double price){
this.name = name;
this.price = price;
}
public double getPrice(){
return price;
}
public String getName(){
return name;
}
}
class Body implements Part{
String name;
double price;
public Body(String name,double price){
this.name = name;
this.price = price;
}
public double getPrice(){
return price;
}
public String getName(){
return name;
}
}
class Car implements Part{
List<Part> parts;
String name;
public Car(String name){
this.name = name;
parts = new ArrayList<Part>();
}
public void addPart(Part part){
parts.add(part);
}
public String getName(){
return name;
}
public String getPartNames(){
StringBuilder sb = new StringBuilder();
for ( Part part: parts){
sb.append(part.getName()).append(" ");
}
return sb.toString();
}
public double getPrice(){
double price = 0;
for ( Part part: parts){
price += part.getPrice();
}
return price;
}
}
public class CompositeDemo{
public static void main(String args[]){
Part engine = new Engine("DiselEngine",15000);
Part trunk = new Trunk("Trunk",10000);
Part body = new Body("Body",12000);
Car car = new Car("Innova");
car.addPart(engine);
car.addPart(trunk);
car.addPart(body);
double price = car.getPrice();
System.out.println("Car name:"+car.getName());
System.out.println("Car parts:"+car.getPartNames());
System.out.println("Car price:"+car.getPrice());
}
}
salida:
Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0
Explicación:
- Parte es una hoja
- El auto contiene muchas partes
- Se han agregado diferentes partes del automóvil al automóvil
- El precio de Car = suma de (Precio de cada Parte )
Consulte la pregunta a continuación para conocer los pros y los contras de la composición y la herencia.
¿Cómo la herencia puede ser peligrosa?
Tomemos un ejemplo
public class X{
public void do(){
}
}
Public Class Y extends X{
public void work(){
do();
}
}
1) Como es claro en el código anterior, la Clase Y tiene un acoplamiento muy fuerte con la clase X. Si algo cambia en la superclase X, Y puede romper dramáticamente. Supongamos que en el futuro la clase X implementa un método de trabajo con la firma debajo
public int work(){
}
El cambio se realiza en la clase X pero hará que la clase Y no sea compilable. ASÍ, este tipo de dependencia puede llegar a cualquier nivel y puede ser muy peligroso. Cada vez que la superclase puede no tener visibilidad completa del código dentro de todas sus subclases y la subclase puede seguir observando todo lo que sucede en suerclass todo el tiempo. Entonces, debemos evitar este acoplamiento fuerte e innecesario.
¿Cómo la composición resuelve este problema?
Veamos revisando el mismo ejemplo
public class X{
public void do(){
}
}
Public Class Y{
X x=new X();
public void work(){
x.do();
}
}
Aquí estamos creando una referencia de la clase X en la clase Y e invocando el método de la clase X creando una instancia de la clase X. Ahora todo ese fuerte acoplamiento se ha ido. La superclase y la subclase son altamente independientes entre sí ahora. Las clases pueden realizar libremente cambios que son peligrosos en la situación de herencia.
2) Segunda muy buena ventaja de la composición en que proporciona flexibilidad de llamada de método Por ejemplo
class X implements R
{}
class Y implements R
{}
public class Test{
R r;
}
En la clase de prueba que utiliza la referencia r, puedo invocar los métodos de la clase X así como la clase Y. Esta flexibilidad nunca estuvo presente en la herencia
3) Otra gran ventaja: pruebas unitarias
public class X{
public void do(){
}
}
Public Class Y{
X x=new X();
public void work(){
x.do();
}
}
En el ejemplo anterior Si no se conoce el estado de x instancia, se puede burlar fácilmente utilizando algunos datos de prueba y todos los métodos pueden probarse fácilmente. Esto no fue posible en absoluto en la herencia, ya que dependías mucho de la superclase para obtener el estado de instancia y ejecutar cualquier método.
4) Otra buena razón por la que debemos evitar la herencia es que Java no admite herencia múltiple.
Tomemos un ejemplo para entender esto:
Public class Transaction {
Banking b;
public static void main(String a[])
{
b=new Deposit();
if(b.deposit()){
b=new Credit();
c.credit();
}
}
}
Bueno saber :
la composición se logra fácilmente en el tiempo de ejecución mientras que la herencia proporciona sus características en tiempo de compilación
composición también se conoce como relación HAS-A y la herencia también se conoce como relación IS-A
Así que conviértelo en un hábito de siempre preferir la composición sobre la herencia por varias razones anteriores.
Aunque tanto la herencia como la composición proporcionan la reutilización del código, la principal diferencia entre la composición y la herencia en Java es que la composición permite la reutilización del código sin ampliarlo, pero para la herencia debe ampliar la clase para reutilizar el código o la funcionalidad. Otra diferencia que surge de este hecho es que al usar Composition puede reutilizar el código incluso para la clase final que no es extensible, pero la herencia no puede reutilizar el código en tales casos. Además, al usar Composition puede reutilizar código de muchas clases, ya que se declaran como solo una variable miembro, pero con Inheritance puede reutilizar código de una sola clase porque en Java solo puede extender una clase, porque la herencia múltiple no es compatible con Java. . Sin embargo, puedes hacer esto en C ++ porque hay una clase que puede extender más de una clase. Por cierto, siempre deberías preferir la composición sobre la herencia en Java , no solo yo, sino incluso lo que Joshua Bloch ha sugerido en su libro.
Composición significa crear un objeto para una clase que tiene relación con esa clase en particular. Supongamos que el alumno tiene relación con las cuentas;
Una herencia es, esta es la clase anterior con la característica extendida. Eso significa que esta nueva clase es la clase anterior con alguna característica extendida. Supongamos que el alumno es un alumno pero todos los alumnos son humanos. Entonces hay una relación con estudiantes y humanos. Esto es Herencia.
Creo que este ejemplo explica claramente las diferencias entre herencia y composición .
En este ejemplo, el problema se resuelve usando herencia y composición. El autor presta atención al hecho de que; en herencia , un cambio en la superclase podría causar problemas en la clase derivada, que la heredará.
Allí también puede ver la diferencia en la representación cuando usa un UML para herencia o composición.
Ellos son absolutamente diferentes. La herencia es una relación "es-a" . La composición es un "has-a" .
Hace la composición teniendo una instancia de otra clase C
como un campo de su clase, en lugar de extender C
Un buen ejemplo en el que la composición hubiera sido mucho mejor que la herencia es java.util.Stack
, que actualmente amplía java.util.Vector
. Esto ahora se considera un error. Un vector de pila "is-NOT-a" ; no se le debe permitir insertar y eliminar elementos arbitrariamente. Debería haber sido composición en su lugar.
Desafortunadamente, es demasiado tarde para rectificar este error de diseño, ya que cambiar la jerarquía de herencia ahora rompería la compatibilidad con el código existente. Si Stack
hubiera usado composición en lugar de herencia, siempre se puede modificar para usar otra estructura de datos sin violar la API .
Recomiendo encarecidamente el libro de Josh Bloch Effective Java 2nd Edition
- Ítem 16: Favorecer la composición sobre la herencia
- Elemento 17: Diseñe y documente por herencia o de lo contrario, prohíba
Un buen diseño orientado a objetos no se trata de extender liberalmente las clases existentes. Tu primer instinto debería ser componer en su lugar.
Ver también:
La composición es cuando algo se compone de distintas partes y tiene una fuerte relación con esas partes. Si la parte principal muere también lo hacen los demás, no pueden tener vida propia. Un ejemplo aproximado es el cuerpo humano. Saca el corazón y todas las otras partes mueren.
La herencia es donde solo toma algo que ya existe y lo usa. No hay una relación fuerte. Una persona puede heredar el patrimonio de su padre, pero él puede prescindir de él.
No conozco Java así que no puedo dar un ejemplo pero puedo proporcionar una explicación de los conceptos.
La composición es tal como suena: creas un objeto al conectar partes.
EDITAR el resto de esta respuesta se basa erróneamente en la siguiente premisa.
Esto se logra con Interfaces.
Por ejemplo, usando el ejemplo de Car
anterior,
Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel
Entonces, con unos pocos componentes teóricos estándar, puede construir su objeto. Entonces es su trabajo completar cómo una House
protege a sus ocupantes y cómo un Car
protege a sus ocupantes.
La herencia es como al revés. Empiezas con un objeto completo (o semi-completo) y reemplazas o sobrescribes los diversos bits que deseas cambiar.
Por ejemplo, MotorVehicle
puede venir con un método Fuelable
y un método de Drive
. Puede dejar el método de Combustible tal como está porque es lo mismo llenar una motocicleta y un automóvil, pero puede anular el método de conducción porque la motocicleta conduce de manera muy diferente a un Car
.
Con la herencia, algunas clases ya están completamente implementadas, y otras tienen métodos que se ven obligados a anular. Con Composition no se te da nada. (pero puede Implementar las interfaces llamando a métodos en otras clases si tiene algo por ahí).
La composición se ve como más flexible, porque si tienes un método como iUsesFuel, puedes tener un método en otro lugar (otra clase, otro proyecto) que simplemente se preocupe por tratar con objetos que pueden ser alimentados, independientemente de si es un auto, barco, estufa, barbacoa, etc. Las interfaces obligan a que las clases que dicen que implementan esa interfaz realmente tengan los métodos de los que se trata esa interfaz. Por ejemplo,
iFuelable Interface:
void AddSomeFuel()
void UseSomeFuel()
int percentageFull()
entonces puedes tener un método en otro lado
private void FillHerUp(iFuelable : objectToFill) {
Do while (objectToFill.percentageFull() <= 100) {
objectToFill.AddSomeFuel();
}
Extraño ejemplo, pero muestra que a este método no le importa lo que se está llenando, porque el objeto implementa iUsesFuel
, se puede llenar. Fin de la historia.
Si utilizó Herencia en su lugar, necesitaría diferentes métodos de FillHerUp
para tratar con MotorVehicles
y Barbecues
, a menos que tuviera algún objeto base "ObjectThatUsesFuel" bastante extraño para heredar.
La composición significa HAS A
Herencia significa IS A
Example
: el automóvil tiene un motor y el automóvil es un automóvil
En la programación esto se representa como:
class Engine {} // The Engine class.
class Automobile {} // Automobile class which is parent to Car class.
class Car extends Automobile { // Car is an Automobile, so Car class extends Automobile class.
private Engine engine; // Car has an Engine so, Car class has an instance of Engine class as its member.
}
La herencia significa reutilizar la funcionalidad completa de una clase. Aquí mi clase tiene que usar todos los métodos de la superclase y mi clase se combinará con la superclase y el código se duplicará en ambas clases en caso de heredar.
Pero podemos superar todos estos problemas cuando usamos la composición para hablar con otra clase. la composición está declarando un atributo de otra clase en mi clase a la que queremos hablar. y qué funcionalidad queremos de esa clase que podemos obtener mediante el uso de ese atributo.
La respuesta dada por @Michael Rodrigues no es correcta (me disculpo, no puedo comentar directamente) y podría generar cierta confusión.
La implementación de la interfaz es una forma de herencia ... cuando implementa una interfaz, no solo está heredando todas las constantes, sino que está comprometiendo su objeto para que sea del tipo especificado por la interfaz; sigue siendo una relación " es-un ". Si un automóvil implementa Rellenable , el carro " es-a " Rellenable , y puede usarse en su código donde quiera que use un Relleno .
La composición es fundamentalmente diferente de la herencia. Cuando usa la composición, está (como la otra nota de las respuestas) haciendo una relación " tiene-a " entre dos objetos, a diferencia de la relación " es-a " que hace cuando usa la herencia .
Entonces, de los ejemplos del automóvil en las otras preguntas, si quisiera decir que un automóvil tiene un tanque de gasolina, usaría la composición de la siguiente manera:
public class Car {
private GasTank myCarsGasTank;
}
Afortunadamente eso borra cualquier malentendido.
No, ambos son diferentes. La composición sigue la relación "HAS-A" y la herencia sigue la relación "IS-A". El mejor ejemplo para la composición fue el patrón estratégico.
como otro ejemplo, considere una clase de automóvil, esto sería un buen uso de la composición, un automóvil "tendría" un motor, una transmisión, neumáticos, asientos, etc. No extendería ninguna de esas clases.
La herencia entre dos clases, donde una clase se extiende a otra, establece una relación " IS A ".
La composición en el otro extremo contiene una instancia de otra clase en su clase que establece la relación " Tiene A ". La composición en Java es útil ya que técnicamente facilita la herencia múltiple.
En Simple Word Agregación significa Tiene una relación ..
La composición es un caso especial de agregación . De una manera más específica, una agregación restringida se llama composición. Cuando un objeto contiene el otro objeto, si el objeto contenido no puede existir sin la existencia de un objeto contenedor, entonces se llama composición. Ejemplo: una clase contiene estudiantes. Un estudiante no puede existir sin una clase. Existe una composición entre clase y estudiantes.
Por qué usar agregación
Reutilización de código
Cuando use Agregación
La reutilización del código también se logra mejor mediante la agregación cuando no hay una relación.
Herencia
La herencia es una relación entre padres e hijos. La herencia significa una relación.
La herencia en java es un mecanismo en el cual un objeto adquiere todas las propiedades y comportamientos del objeto principal.
Uso de herencia en Java 1 Reutilización de código. 2 Agregue una característica adicional en la clase secundaria así como la anulación de métodos (para que se pueda lograr el polimorfismo en tiempo de ejecución).
Herencias Vs composición.
Las herencias y la composición se usan para volver a usar y para extender el comportamiento de clase.
Las herencias utilizan principalmente en un modelo de programación de algoritmos familiares, como el tipo de relación IS-A, que significa un tipo similar de objeto. Ejemplo.
- Duster es un coche
- Safari es un coche
Estos son de la familia de Car.
La composición representa el tipo de relación HAS-A. Muestra la capacidad de un objeto como Duster tiene Five Gears, Safari tiene cuatro Gears, etc. Siempre que necesitemos ampliar la capacidad de una clase existente, utilicemos la composición. Ejemplo , necesitamos agregar un engranaje más en el objeto Duster, luego tenemos que crear un objeto de engranaje más y componerlo para el objeto Duster.
No deberíamos hacer los cambios en la clase base hasta / a menos que todas las clases derivadas necesiten esas funcionalidades. Para este escenario, deberíamos usar Composition.Such como
Clase A Derivado de la Clase B
Clase A Derivada de Clase C
Clase A Derivada por la Clase D.
Cuando agregamos cualquier funcionalidad en la clase A, está disponible para todas las subclases, incluso cuando la Clase C y D no requieren esa funcionalidad. Para este escenario, necesitamos crear una clase separada para esas funcionalidades y componerla para la clase requerida ( aquí está la clase B).
A continuación está el ejemplo:
// This is a base class
public abstract class Car
{
//Define prototype
public abstract void color();
public void Gear() {
Console.WriteLine("Car has a four Gear");
}
}
// Here is the use of inheritence
// This Desire class have four gears.
// But we need to add one more gear that is Neutral gear.
public class Desire : Car
{
Neutral obj = null;
public Desire()
{
// Here we are incorporating neutral gear(It is the use of composition).
// Now this class would have five gear.
obj = new Neutral();
obj.NeutralGear();
}
public override void color()
{
Console.WriteLine("This is a white color car");
}
}
// This Safari class have four gears and it is not required the neutral
// gear and hence we don''t need to compose here.
public class Safari :Car{
public Safari()
{ }
public override void color()
{
Console.WriteLine("This is a red color car");
}
}
// This class represents the neutral gear and it would be used as a composition.
public class Neutral {
public void NeutralGear() {
Console.WriteLine("This is a Neutral Gear");
}
}
La herencia saca la relación IS-A . La composición saca la relación HAS-A . El patrón de Statergy explica que la Composición debe usarse en casos donde hay familias de algoritmos que definen un comportamiento particular.
Ejemplo clásico de una clase de pato que implementa un comportamiento de vuelo.
public interface Flyable{
public void fly();
}
public class Duck {
Flyable fly;
public Duck(){
fly=new BackwardFlying();
}
}
Por lo tanto, podemos tener múltiples clases que implementan vuelo, por ejemplo:
public class BackwardFlying implements Flyable{
public void fly(){
Systemout.println("Flies backward ");
}
}
public class FastFlying implements Flyable{
public void fly(){
Systemout.println("Flies 100 miles/sec");
}
}
Si hubiera sido por herencia, tendríamos dos clases diferentes de aves que implementan la función de volar una y otra vez. Esta herencia y composición son completamente diferentes.