Composição e herança são iguais? Se eu quiser implementar o padrão de composição, como posso fazer isso em Java?
Composição e herança são iguais? Se eu quiser implementar o padrão de composição, como posso fazer isso em Java?
Respostas:
Eles são absolutamente diferentes. A herança é um relacionamento "é-a" . A composição é um "tem-a" .
Você faz composição tendo uma instância de outra classe C
como um campo da sua classe, em vez de se estendendo C
. Um bom exemplo de composição seria muito melhor do que a herança java.util.Stack
, que atualmente se estende java.util.Vector
. Agora isso é considerado um erro. Um vetor "is-NOT-a" da pilha ; você não deve inserir e remover elementos arbitrariamente. Deveria ter sido composição em seu lugar.
Infelizmente, é tarde demais para corrigir esse erro de design, já que alterar a hierarquia de herança agora quebraria a compatibilidade com o código existente. Se havia Stack
usado composição em vez de herança, sempre pode ser modificado para usar outra estrutura de dados sem violar a API .
Eu recomendo o livro de Josh Bloch, Effective Java 2nd Edition
Um bom design orientado a objetos não se estende liberalmente às classes existentes. Seu primeiro instinto deve ser compor.
Veja também:
Composição significa HAS A
HerançaIS A
Example
: O carro tem um motor e o carro é um automóvel
Na programação, isso é representado 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.
}
:-/
type
campo de TypeEnum
Como a herança pode ser perigosa?
Vamos dar um exemplo
public class X{
public void do(){
}
}
Public Class Y extends X{
public void work(){
do();
}
}
1) Como está claro no código acima, a Classe Y possui um acoplamento muito forte com a classe X. Se algo mudar na superclasse X, Y poderá quebrar drasticamente. Suponha que, no futuro, a classe X implemente um método de trabalho com a assinatura abaixo
public int work(){
}
A alteração é feita na classe X, mas tornará a classe Y compilável. Portanto, esse tipo de dependência pode subir para qualquer nível e pode ser muito perigoso. Toda vez que a superclasse pode não ter total visibilidade para codificar dentro de todas as suas subclasses, a subclasse pode ficar observando o que está acontecendo na superclasse o tempo todo. Portanto, precisamos evitar esse acoplamento forte e desnecessário.
Como a composição resolve esse problema?
Vamos ver revisando o mesmo exemplo
public class X{
public void do(){
}
}
Public Class Y{
X x = new X();
public void work(){
x.do();
}
}
Aqui, estamos criando referência da classe X na classe Y e invocando o método da classe X, criando uma instância da classe X. Agora todo esse forte acoplamento se foi. Superclasse e subclasse são altamente independentes uma da outra agora. As aulas podem fazer livremente alterações perigosas na situação de herança.
2) Segunda vantagem muito boa da composição, pois fornece flexibilidade de chamada de método, por exemplo:
class X implements R
{}
class Y implements R
{}
public class Test{
R r;
}
Na classe Teste, usando a referência r, posso chamar métodos da classe X e da classe Y. Essa flexibilidade nunca esteve presente na herança
3) Outra grande vantagem: Teste de unidade
public class X {
public void do(){
}
}
Public Class Y {
X x = new X();
public void work(){
x.do();
}
}
No exemplo acima, se o estado da instância x não for conhecido, ele poderá ser facilmente zombado usando alguns dados de teste e todos os métodos poderão ser facilmente testados. Isso não foi possível na herança, pois você dependia muito da superclasse para obter o estado da instância e executar qualquer método.
4) Outra boa razão pela qual devemos evitar a herança é que o Java não suporta herança múltipla.
Vamos dar um exemplo para entender isso:
Public class Transaction {
Banking b;
public static void main(String a[])
{
b = new Deposit();
if(b.deposit()){
b = new Credit();
c.credit();
}
}
}
Bom saber :
composição é facilmente alcançada em tempo de execução, enquanto a herança fornece seus recursos em tempo de compilação
composição também é conhecida como relação HAS-A e herança também é conhecida como relação IS-A
Portanto, crie o hábito de sempre preferir a composição à herança por várias razões acima.
A resposta dada por @Michael Rodrigues não está correta (peço desculpas; não posso comentar diretamente) e pode levar a alguma confusão.
A implementação de interface é uma forma de herança ... quando você implementa uma interface, não está apenas herdando todas as constantes, mas também comprometendo seu objeto com o tipo especificado pela interface; ainda é um " é-um relacionamento ". Se um carro implementa o Fillable , o carro " é-a " Fillable e pode ser usado em seu código onde quer que você use um Fillable .
A composição é fundamentalmente diferente da herança. Ao usar a composição, você está (como as outras respostas observam) fazendo um relacionamento " tem um " entre dois objetos, em oposição ao relacionamento " é um " que você cria ao usar a herança .
Portanto, a partir dos exemplos de carros nas outras perguntas, se eu quisesse dizer que um carro " tem um tanque de gasolina", usaria a composição da seguinte maneira:
public class Car {
private GasTank myCarsGasTank;
}
Espero que isso esclareça qualquer mal-entendido.
A herança traz à tona a relação IS-A . Composição traz à tona a relação HAS-A . O padrão de estratégia explica que a composição deve ser usada nos casos em que há famílias de algoritmos que definem um comportamento específico.
Exemplo clássico de uma classe de pato que implementa um comportamento de vôo.
public interface Flyable{
public void fly();
}
public class Duck {
Flyable fly;
public Duck(){
fly = new BackwardFlying();
}
}
Assim, podemos ter várias classes que implementam o vôo, por exemplo:
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 por herança, teríamos duas classes diferentes de pássaros que implementam a função de voar repetidamente. Portanto, herança e composição são completamente diferentes.
A composição é exatamente como parece - você cria um objeto conectando partes.
EDITAR o restante desta resposta é erroneamente baseado na seguinte premissa.
Isso é realizado com interfaces.
Por exemplo, usando o Car
exemplo acima,
Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel
Assim, com alguns componentes teóricos padrão, você pode construir seu objeto. É seu trabalho preencher como a House
protege seus ocupantes e como a Car
protege seus ocupantes.
A herança é como o contrário. Você começa com um objeto completo (ou semi-completo) e substitui ou substitui os vários bits que deseja alterar.
Por exemplo, MotorVehicle
pode vir com um Fuelable
método e Drive
método Você pode deixar o método Fuel como está, porque é o mesmo que encher uma moto e um carro, mas você pode substituir o Drive
método porque a Moto dirige de maneira muito diferente de a Car
.
Com a herança, algumas classes já estão completamente implementadas e outras possuem métodos que você é forçado a substituir. Com a composição, nada é dado a você. (mas você pode implementar as interfaces chamando métodos em outras classes se houver algo por aí).
A composição é vista como mais flexível, porque se você tiver um método como iUsesFuel, poderá ter um método em outro lugar (outra classe, outro projeto) que se preocupe apenas em lidar com objetos que podem ser abastecidos, independentemente de se tratar de um carro, barco, fogão, churrasco, etc. As interfaces determinam que as classes que dizem que implementam essa interface tenham realmente os métodos que essa interface trata. Por exemplo,
iFuelable Interface:
void AddSomeFuel()
void UseSomeFuel()
int percentageFull()
então você pode ter um método em outro lugar
private void FillHerUp(iFuelable : objectToFill) {
Do while (objectToFill.percentageFull() <= 100) {
objectToFill.AddSomeFuel();
}
Exemplo estranho, mas mostra que esse método não se importa com o que está preenchendo, porque o objeto implementa iUsesFuel
, pode ser preenchido. Fim da história.
Se você usasse Herança em vez disso, precisaria de FillHerUp
métodos diferentes para lidar com , MotorVehicles
e Barbecues
, a menos que tenha algum objeto base "ObjectThatUsesFuel" bastante estranho do qual herdar.
ThisCase
, não dentro camelCase
. Portanto, é melhor nomear suas interfaces IDrivable
, etc. Você pode não precisar do "I" se reagrupar todas as suas interfaces em um pacote corretamente.
Composição e herança são iguais?
Eles não são iguais.
Composição : Permite que um grupo de objetos seja tratado da mesma maneira que uma única instância de um objeto. A intenção de um composto é "compor" objetos em estruturas de árvore para representar hierarquias de partes inteiras
Herança : uma classe herda campos e métodos de todas as suas superclasses, sejam diretas ou indiretas. Uma subclasse pode substituir os métodos herdados ou pode ocultar campos ou métodos herdados.
Se eu quiser implementar o padrão de composição, como posso fazer isso em Java?
O artigo da Wikipedia é bom o suficiente para implementar o padrão composto em java.
Principais Participantes:
Componente :
Folha :
Composto :
Exemplo de código para entender o padrão Composite :
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());
}
}
resultado:
Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0
Explicação:
Consulte a pergunta abaixo para obter os prós e contras da composição e herança.
como outro exemplo, considere uma classe de carro, isso seria um bom uso da composição, um carro "teria" um motor, uma transmissão, pneus, assentos etc. Não estenderia nenhuma dessas classes.
Composição é onde algo é composto de partes distintas e tem uma forte relação com essas partes. Se a parte principal morre, o mesmo ocorre com as outras, elas não podem ter vida própria. Um exemplo aproximado é o corpo humano. Retire o coração e todas as outras partes morrem.
A herança é onde você apenas pega algo que já existe e o usa. Não há um relacionamento forte. Uma pessoa pode herdar a propriedade de seu pai, mas pode ficar sem ela.
Como não conheço Java, não posso fornecer um exemplo, mas posso fornecer uma explicação dos conceitos.
A herança entre duas classes, onde uma classe estende outra classe, estabelece " IS A ".
A composição do outro lado contém uma instância de outra classe na sua classe e estabelece um relacionamento " Tem um ". A composição em java é útil, pois tecnicamente facilita a herança múltipla.
Na agregação simples de palavras, significa que possui um relacionamento.
A composição é um caso especial de agregação . De uma maneira mais específica, uma agregação restrita é chamada composição. Quando um objeto contém o outro objeto, se o objeto contido não puder existir sem a existência do objeto contêiner, ele será chamado de composição. Exemplo: Uma turma contém alunos. Um aluno não pode existir sem uma aula. Existe composição entre turma e alunos.
Por que usar agregação
Reutilização de código
Quando usar agregação
A reutilização de código também é melhor alcançada por agregação quando não há um navio de Relação
Herança
A herança é um relacionamento entre pais e filhos A herança significa que é um relacionamento
A herança em java é um mecanismo no qual um objeto adquire todas as propriedades e comportamentos do objeto pai.
Usando herança no Java 1 Code Reusability. 2 Adicione Recurso Extra na Classe Criança, bem como Substituição de Método (para que o polimorfismo em tempo de execução possa ser alcançado).
Embora Inheritance e Composition forneçam capacidade de reutilização de código, a principal diferença entre Composition e Herança em Java é que o Composition permite a reutilização de código sem estendê-lo, mas para Herança você deve estender a classe para qualquer reutilização de código ou funcionalidade. Outra diferença que resulta desse fato é que, ao usar o Composition, você pode reutilizar o código até para a classe final que não é extensível, mas a Herança não pode reutilizar o código nesses casos. Além disso, usando Composition, você pode reutilizar o código de muitas classes, pois elas são declaradas apenas como uma variável de membro, mas com o Herança, você pode reutilizar o formulário do código apenas uma classe, porque em Java você pode estender apenas uma classe, porque o recurso Herança múltipla não é suportado em Java. . Você pode fazer isso em C ++, porque uma classe pode estender mais de uma classe. BTW, você deve sempreprefiro Composition a Herança em Java , não sou apenas eu, mas até Joshua Bloch sugeriu em seu livro
Eu acho que este exemplo explica claramente as diferenças entre herança e composição .
Neste exemplo, o problema é resolvido usando herança e composição. O autor presta atenção ao fato de que; na herança , uma mudança na superclasse pode causar problemas na classe derivada, que a herdam.
Também é possível ver a diferença na representação quando você usa uma UML para herança ou composição.
Heranças versus Composição.
Heranças e composição são usadas para reutilização e extensão do comportamento da classe.
As heranças usadas principalmente em um modelo de programação de algoritmos de família, como o tipo de relação IS-A, significam tipos semelhantes de objetos. Exemplo.
Estes são pertencem à família Car.
A composição representa o tipo de relacionamento HAS-A. Mostra a capacidade de um objeto como o Duster tem cinco marchas, o Safari tem quatro marchas etc. Sempre que precisarmos estender a capacidade de uma classe existente, use a composição. Exemplo , precisamos adicionar mais uma engrenagem no objeto Duster, em seguida, precisamos criar mais um objeto de engrenagem e compor ao objeto Duster.
Não devemos fazer as alterações na classe base até / a menos que todas as classes derivadas precisem dessas funcionalidades. Nesse cenário, devemos usar Composition.Such
classe A Derivado pela classe B
Classe A Derivada pela Classe C
Classe A Derivada pela Classe D.
Quando adicionamos qualquer funcionalidade na classe A, ela fica disponível para todas as subclasses, mesmo quando as classes C e D não exigem essa funcionalidade. Para esse cenário, precisamos criar uma classe separada para essa funcionalidade e compor a classe necessária ( aqui é a classe B).
Abaixo está o exemplo:
// 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");
}
}
Composição significa criar um objeto para uma classe que tenha relação com essa classe específica. Suponha que o aluno tenha relação com as contas;
Uma herança é que esta é a classe anterior com o recurso estendido. Isso significa que esta nova classe é a classe antiga com algum recurso estendido. Suponha que Aluno seja Aluno, mas Todos os Alunos são Humanos. Portanto, existe um relacionamento com aluno e humano. Isso é herança.
Não, ambos são diferentes. A composição segue o relacionamento "HAS-A" e a herança segue o relacionamento "IS-A". O melhor exemplo de composição foi o padrão estratégico.
Herança significa reutilizar a funcionalidade completa de uma classe. Aqui, minha classe precisa usar todos os métodos da superclasse e minha classe será totalmente acoplada à superclasse e o código será duplicado em ambas as classes em caso de herança.
Mas podemos superar todos esses problemas quando usamos a composição para conversar com outra classe. composição está declarando um atributo de outra classe na minha classe com a qual queremos conversar. e que funcionalidade queremos dessa classe que podemos obter usando esse atributo.