Composizione ed ereditarietà sono uguali? Se voglio implementare il modello di composizione, come posso farlo in Java?
Composizione ed ereditarietà sono uguali? Se voglio implementare il modello di composizione, come posso farlo in Java?
Risposte:
Sono assolutamente diversi. L'ereditarietà è una relazione "is-a" . La composizione è una "has-a" .
Fai composizione avendo un'istanza di un'altra classe C
come campo della tua classe, invece di estenderla C
. Un buon esempio in cui la composizione sarebbe stata molto meglio dell'eredità è java.util.Stack
, che attualmente si estende java.util.Vector
. Questo è ora considerato un errore. Uno stack "NON-NON-un" vettore; non dovresti essere autorizzato a inserire e rimuovere elementi arbitrariamente. Avrebbe dovuto essere invece composizione.
Sfortunatamente è troppo tardi per correggere questo errore di progettazione, poiché la modifica della gerarchia dell'ereditarietà comprometterebbe la compatibilità con il codice esistente. Aveva Stack
utilizzato la composizione anziché l'ereditarietà, può sempre essere modificata per utilizzare un'altra struttura di dati senza violare l'API .
Consiglio vivamente il libro di Josh Bloch, Effective Java 2nd Edition
Una buona progettazione orientata agli oggetti non riguarda l'estensione libera delle classi esistenti. Il tuo primo istinto dovrebbe essere quello di comporre invece.
Guarda anche:
Composizione significa HAS A
ereditarietàIS A
Example
: Auto ha un motore e auto è un Automobile
Nella programmazione questo è rappresentato come:
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.
}
:-/
type
campo di tipoEnum
In che modo l'eredità può essere pericolosa?
Facciamo un esempio
public class X{
public void do(){
}
}
Public Class Y extends X{
public void work(){
do();
}
}
1) Come indicato nel codice sopra, la Classe Y ha un accoppiamento molto forte con la Classe X. Se qualcosa cambia nella superclasse X, Y potrebbe rompersi drammaticamente. Supponiamo che in futuro la classe X attui un metodo di lavoro con la seguente firma
public int work(){
}
Il cambiamento viene effettuato nella classe X ma renderà la classe Y incompatibile. Quindi questo tipo di dipendenza può salire a qualsiasi livello e può essere molto pericoloso. Ogni volta che la superclasse potrebbe non avere la piena visibilità del codice all'interno di tutte le sue sottoclassi e la sottoclasse può continuare a notare ciò che sta accadendo nella superclasse per tutto il tempo. Quindi dobbiamo evitare questo accoppiamento forte e inutile.
In che modo la composizione risolve questo problema?
Vediamo rivedendo lo stesso esempio
public class X{
public void do(){
}
}
Public Class Y{
X x = new X();
public void work(){
x.do();
}
}
Qui stiamo creando il riferimento della classe X nella classe Y e invocando il metodo della classe X creando un'istanza della classe X. Ora tutto quel forte accoppiamento è sparito. Superclass e sottoclasse sono altamente indipendenti l'uno dall'altro ora. Le classi possono liberamente apportare modifiche che erano pericolose nella situazione ereditaria.
2) Secondo ottimo vantaggio della composizione in quanto offre flessibilità di metodo di chiamata, ad esempio:
class X implements R
{}
class Y implements R
{}
public class Test{
R r;
}
Nella classe Test usando il riferimento r posso invocare i metodi della classe X e della classe Y. Questa flessibilità non è mai stata lì in eredità
3) Un altro grande vantaggio: test unitari
public class X {
public void do(){
}
}
Public Class Y {
X x = new X();
public void work(){
x.do();
}
}
Nell'esempio sopra, se lo stato dell'istanza x non è noto, può essere facilmente simulato usando alcuni dati di test e tutti i metodi possono essere facilmente testati. Questo non era affatto possibile in eredità poiché eri fortemente dipendente dalla superclasse per ottenere lo stato di istanza ed eseguire qualsiasi metodo.
4) Un altro buon motivo per cui dovremmo evitare l'ereditarietà è che Java non supporta l'ereditarietà multipla.
Facciamo un esempio per capirlo:
Public class Transaction {
Banking b;
public static void main(String a[])
{
b = new Deposit();
if(b.deposit()){
b = new Credit();
c.credit();
}
}
}
Buono a sapersi :
la composizione è facilmente raggiungibile in fase di esecuzione mentre l'ereditarietà fornisce le sue funzionalità in fase di compilazione
la composizione è anche conosciuta come relazione HAS-A e l'eredità è anche nota come relazione IS-A
Quindi prendi l'abitudine di preferire sempre la composizione all'eredità per vari motivi di cui sopra.
La risposta data da @Michael Rodrigues non è corretta (chiedo scusa; non sono in grado di commentare direttamente) e potrebbe creare confusione.
L'implementazione dell'interfaccia è una forma di ereditarietà ... quando si implementa un'interfaccia, non si eredita solo tutte le costanti, si impegna il proprio oggetto ad essere del tipo specificato dall'interfaccia; è ancora una relazione " is-a ". Se un'auto implementa Fillable , l'auto " è-a " Fillable e può essere utilizzata nel tuo codice ovunque tu utilizzi un Fillable .
La composizione è sostanzialmente diversa dall'eredità. Quando usi la composizione, stai (come notano le altre risposte) creando una relazione " has-a " tra due oggetti, al contrario della relazione " is-a " che crei quando usi l'ereditarietà .
Quindi, dagli esempi di auto nelle altre domande, se volessi dire che un'auto " ha " un serbatoio di gas, userei la composizione, come segue:
public class Car {
private GasTank myCarsGasTank;
}
Spero che questo chiarisca ogni equivoco.
L'ereditarietà mette in evidenza la relazione IS-A . La composizione mette in evidenza la relazione HAS-A . Il modello di strategia spiega che la composizione dovrebbe essere usata nei casi in cui esistono famiglie di algoritmi che definiscono un comportamento particolare.
Esempio classico di una classe di anatre che implementa un comportamento di volo.
public interface Flyable{
public void fly();
}
public class Duck {
Flyable fly;
public Duck(){
fly = new BackwardFlying();
}
}
Quindi possiamo avere più classi che implementano il volo, ad esempio:
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");
}
}
Se fosse stato per eredità, avremmo due diverse classi di uccelli che implementano ripetutamente la funzione fly. Quindi eredità e composizione sono completamente diverse.
La composizione è come sembra: si crea un oggetto collegando le parti.
MODIFICA il resto di questa risposta si basa erroneamente sulla premessa seguente.
Questo si ottiene con le interfacce.
Ad esempio, usando l' Car
esempio sopra,
Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel
Quindi con alcuni componenti teorici standard puoi costruire il tuo oggetto. È quindi il tuo lavoro compilare il modo in cui House
protegge i suoi occupanti e come Car
protegge i suoi occupanti.
L'ereditarietà è come il contrario. Inizi con un oggetto completo (o semi-completo) e sostituisci o Sostituisci i vari bit che vuoi cambiare.
Ad esempio, MotorVehicle
può venire con un Fuelable
metodo e un Drive
metodo. È possibile abbandonare il metodo Fuel in quanto è lo stesso per riempire una moto e un'auto, ma è possibile ignorare il Drive
metodo perché la motocicletta guida in modo molto diverso da unCar
.
Con l'ereditarietà, alcune classi sono già completamente implementate e altre hanno metodi che sei costretto a scavalcare. Con Composizione non ti viene dato niente. (ma puoi implementare le interfacce chiamando metodi in altre classi se ti capita di avere qualcosa in giro).
La composizione è vista come più flessibile, perché se hai un metodo come iUsesFuel, puoi avere un metodo da qualche altra parte (un'altra classe, un altro progetto) che si preoccupa solo di gestire oggetti che possono essere alimentati, indipendentemente dal fatto che sia un'auto, barca, fornello, barbecue, ecc. Le interfacce richiedono che le classi che affermano di implementare quell'interfaccia abbiano effettivamente i metodi su cui quell'interfaccia si basa. Per esempio,
iFuelable Interface:
void AddSomeFuel()
void UseSomeFuel()
int percentageFull()
allora puoi avere un metodo da qualche altra parte
private void FillHerUp(iFuelable : objectToFill) {
Do while (objectToFill.percentageFull() <= 100) {
objectToFill.AddSomeFuel();
}
Strano esempio, ma mostra che a questo metodo non importa cosa si sta riempiendo, poiché l'oggetto implementa iUsesFuel
, può essere riempito. Fine della storia.
Se invece avessi usato Ereditarietà, avresti bisogno di FillHerUp
metodi diversi per gestire MotorVehicles
e Barbecues
, a meno che tu non avessi qualche oggetto base "ObjectThatUsesFuel" piuttosto strano da cui ereditare.
ThisCase
, non in camelCase
. Pertanto è meglio nominare le interfacce IDrivable
, ecc. Potrebbe non essere necessario l'io se si raggruppano correttamente tutte le interfacce in un pacchetto.
Composizione ed ereditarietà sono uguali?
Non sono uguali.
Composizione : consente a un gruppo di oggetti di essere trattato allo stesso modo di una singola istanza di un oggetto. L'intento di un composito è di "comporre" oggetti in strutture ad albero per rappresentare gerarchie intere
Eredità : una classe eredita campi e metodi da tutte le sue superclassi, dirette o indirette. Una sottoclasse può ignorare i metodi che eredita oppure può nascondere campi o metodi che eredita.
Se voglio implementare il modello di composizione, come posso farlo in Java?
L' articolo di Wikipedia è abbastanza buono per implementare pattern compositi in Java.
Partecipanti chiave:
Componente :
Foglia :
Composito :
Esempio di codice per comprendere il modello composito :
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());
}
}
produzione:
Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0
Spiegazione:
Fare riferimento alla domanda di seguito per Pro e contro di composizione ed ereditarietà.
come altro esempio, considera una classe di auto, questo sarebbe un buon uso della composizione, un'auto "avrebbe" un motore, una trasmissione, pneumatici, sedili, ecc. Non estenderebbe nessuna di quelle classi.
La composizione è il punto in cui qualcosa è composto da parti distinte e ha una forte relazione con quelle parti. Se la parte principale muore, così fanno gli altri, non possono avere una vita propria. Un esempio approssimativo è il corpo umano. Elimina il cuore e tutte le altre parti muoiono.
L'ereditarietà è dove prendi qualcosa che esiste già e lo usi. Non esiste una relazione forte. Una persona potrebbe ereditare la proprietà del padre, ma può farne a meno.
Non conosco Java, quindi non posso fornire un esempio ma posso fornire una spiegazione dei concetti.
Ereditarietà tra due classi, in cui una classe estende un'altra classe stabilisce la relazione " IS A ".
La composizione all'altra estremità contiene un'istanza di un'altra classe nella tua classe stabilisce una relazione " Ha A ". La composizione in Java è utile poiché facilita tecnicamente l'ereditarietà multipla.
In Simple Word Aggregation significa che ha una relazione.
La composizione è un caso speciale di aggregazione . In un modo più specifico, un'aggregazione limitata è chiamata composizione. Quando un oggetto contiene l'altro oggetto, se l'oggetto contenuto non può esistere senza l'esistenza di un oggetto contenitore, allora si chiama composizione. Esempio: una classe contiene studenti. Uno studente non può esistere senza una lezione. Esiste una composizione tra classe e studenti.
Perché usare l'aggregazione
Riutilizzabilità del codice
Quando si utilizza l'aggregazione
Il riutilizzo del codice si ottiene anche meglio dall'aggregazione quando non esiste una nave relazione
Eredità
L'ereditarietà è una relazione genitore figlio L'ereditarietà è una relazione
L'ereditarietà in Java è un meccanismo in cui un oggetto acquisisce tutte le proprietà e i comportamenti dell'oggetto genitore.
Utilizzo dell'ereditarietà nella riusabilità del codice Java 1. 2 Aggiungi funzionalità extra nella classe figlio e metodo Override (in modo da poter ottenere il polimorfismo di runtime).
Sebbene sia l'ereditarietà sia la composizione forniscano riusabilità del codice, la principale differenza tra composizione ed ereditarietà in Java è che Composizione consente il riutilizzo del codice senza estenderlo, ma per Ereditarietà è necessario estendere la classe per qualsiasi riutilizzo di codice o funzionalità. Un'altra differenza che deriva da questo fatto è che usando la composizione è possibile riutilizzare il codice anche per la classe finale che non è estensibile ma l'ereditarietà non può riutilizzare il codice in tali casi. Inoltre, usando Composizione puoi riutilizzare il codice di molte classi in quanto sono dichiarate come solo una variabile membro, ma con Ereditarietà puoi riutilizzare il codice da una sola classe perché in Java puoi estendere solo una classe, poiché l'ereditarietà multipla non è supportata in Java . Puoi farlo in C ++ perché una classe può estendere più di una classe. A proposito, dovresti semprepreferisco la composizione all'ereditarietà in Java , non sono solo io ma anche Joshua Bloch ha suggerito nel suo libro
Penso che questo esempio spieghi chiaramente le differenze tra eredità e composizione .
In questo esempio, il problema viene risolto utilizzando l'ereditarietà e la composizione. L'autore presta attenzione al fatto che; in eredità , un cambiamento nella superclasse potrebbe causare problemi nella classe derivata, che la eredita.
Lì puoi anche vedere la differenza nella rappresentazione quando usi un UML per ereditarietà o composizione.
Eredità contro composizione.
Le eredità e la composizione sono entrambe utilizzate per la riutilizzabilità e l'estensione del comportamento di classe.
Le ereditarietà si usano principalmente in un modello di programmazione con algoritmo di famiglia come il tipo di relazione IS-A significa un tipo simile di oggetto. Esempio.
Questi appartengono alla famiglia Car.
La composizione rappresenta il tipo di relazione HAS-A. Mostra l'abilità di un oggetto come Duster ha cinque ingranaggi, Safari ha quattro ingranaggi ecc. Ogni volta che è necessario estendere l'abilità di una classe esistente, utilizzare la composizione. Esempio, dobbiamo aggiungere un altro ingranaggio nell'oggetto Duster, quindi dobbiamo creare un altro oggetto Gear e comporlo nell'oggetto Duster.
Non dovremmo apportare modifiche alla classe di base fino a / a meno che tutte le classi derivate non necessitino di tale funzionalità. Per questo scenario dovremmo usare Composizione.
classe A derivata dalla classe B
Classe A derivata dalla Classe C
Classe A derivata dalla Classe D.
Quando aggiungiamo qualsiasi funzionalità nella classe A, questa è disponibile per tutte le sottoclassi anche quando le classi C e D non richiedono tale funzionalità. Per questo scenario dobbiamo creare una classe separata per tali funzionalità e comporla nella classe richiesta ( ecco la classe B).
Di seguito è riportato l'esempio:
// 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");
}
}
Composizione significa creare un oggetto per una classe che ha relazione con quella particolare classe. Supponiamo che lo studente abbia rapporti con gli Account;
Un'eredità è, questa è la classe precedente con la funzionalità estesa. Ciò significa che questa nuova classe è la vecchia con alcune funzionalità estese. Supponiamo che Studente sia Studente ma Tutti gli Studenti sono Umani. Quindi c'è una relazione con studenti e umani. Questa è eredità.
No, entrambi sono diversi. La composizione segue la relazione "HAS-A" e l'eredità segue la relazione "IS-A". Il miglior esempio di composizione è stato il modello strategico.
Ereditarietà significa riutilizzare la funzionalità completa di una classe, qui la mia classe deve usare tutti i metodi della superclasse e la mia classe sarà titolata accoppiata alla superclasse e il codice sarà duplicato in entrambe le classi in caso di ereditarietà.
Ma possiamo superare tutti questi problemi quando usiamo la composizione per parlare con un'altra classe. la composizione sta dichiarando un attributo di un'altra classe nella mia classe con cui vogliamo parlare. e quale funzionalità vogliamo da quella classe che possiamo ottenere usando quell'attributo.