Разница между наследованием и композицией

состав наследства и то же? Если я хочу реализовать шаблон композиции, как я могу это сделать на Java?

17 ответов


они абсолютно разные. Наследование-это "is-a" отношения. Композиция - это "есть".

Вы делаете композицию, имея экземпляр другого класса C в поле вашего класса, вместо расширения C. Хорошим примером, где композиция была бы намного лучше, чем наследование, является java.util.Stack, который в настоящее время распространяется java.util.Vector. Теперь это считается ошибкой. Стек "это-не" вектор; вы не должны быть допускается вставлять и удалять элементы произвольно. Это должна была быть композиция.

к сожалению, слишком поздно исправлять эту ошибку дизайна, так как изменение иерархии наследования теперь нарушит совместимость с существующим кодом. Had Stack используемая композиция вместо наследования всегда может быть изменена для использования другой структуры данных без нарушения API.

я настоятельно рекомендую книгу Джоша Блоха эффективная Java 2nd Издание

  • пункт 16: предпочтение композиции над наследованием
  • пункт 17: дизайн и документ для наследования или же запретить его

хороший объектно-ориентированный дизайн-это не либеральное расширение существующих классов. Ваш первый инстинкт должен быть, чтобы вместо того, чтобы сочинять.


Читайте также:


состав средств HAS A
Наследование означает IS A

Example: автомобиль есть двигатель и автомобиль это автомобиль

в программировании это представлено так:

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.
}

как наследование может быть опасным ?

давайте возьмем пример

public class X{    
   public void do(){    
   }    
}    
Public Class Y extends X{
   public void work(){    
       do();    
   }
}

1) Как ясно в приведенном выше коде , класс Y имеет очень сильную связь с классом X. Если что-либо изменится в суперклассе X , Y может резко сломаться. Предположим, в будущем класс X реализует метод работы с нижеприведенной сигнатурой

public int work(){
}

изменение выполняется в классе X, но это сделает класс Y несопоставимым. Таким образом, этот вид зависимости может подняться до любого уровня, и это может быть опасно. Каждый у суперкласса времени может не быть полной видимости для кода внутри всех его подклассов, и подкласс может постоянно замечать, что происходит в suerclass. Поэтому нам нужно избегать этой сильной и ненужной связи.

как композиция решает эту проблему?

давайте посмотрим, изменив тот же пример

public class X{
    public void do(){
    }
}

Public Class Y{
    X x=new X();    
    public void work(){    
        x.do();
    }
}

здесь мы создаем ссылку на класс X в классе Y и вызываем метод класса X, создавая экземпляр класса X. Теперь все так сильно ... связь пропала. Суперкласс и подкласс теперь очень независимы друг от друга. Классы могут свободно вносить изменения, которые были опасны в ситуации наследования.

2) Второе очень хорошее преимущество состава в том, что он обеспечивает гибкость вызова метода, например

class X implements R
{}
class Y implements R
{}

public class Test{    
    R r;    
}

в тестовом классе с помощью ссылки r я могу вызывать методы класса X, а также класса Y. Такой гибкости никогда не было в наследстве

3) другое большое преимущество : блок тестирование

public class X{
    public void do(){
    }
}

Public Class Y{
    X x=new X();    
    public void work(){    
        x.do();    
    }    
}

в приведенном выше примере, если состояние экземпляра x неизвестно, его можно легко высмеять, используя некоторые тестовые данные, и все методы могут быть легко протестированы. Это было невозможно вообще в наследовании, поскольку вы сильно зависели от суперкласса, чтобы получить состояние экземпляра и выполнить любой метод.

4) Еще одна хорошая причина, почему мы должны избегать наследования заключается в том, что Java не поддерживает множественное наследование.

давайте возьмем пример, чтобы понять это :

Public class Transaction {
    Banking b;
    public static void main(String a[])    
    {    
        b=new Deposit();    
        if(b.deposit()){    
            b=new Credit();
            c.credit();    
        }
    }
}

полезно знать :

  1. состав легко достигается во время выполнения, в то время как наследование предоставляет свои функции во время компиляции

  2. композиция также известна как HAS-a relation и наследование также известно как IS-a relation

поэтому сделайте это привычкой всегда предпочитать композицию наследованию по различным вышеуказанным причинам.


ответ, данный @Michael Rodrigues, неверен (я прошу прощения, я не могу комментировать напрямую) и может привести к некоторой путанице.

реализация интерфейса является формой наследования... когда вы реализуете интерфейс, вы не только наследуете все константы, вы фиксируете, что ваш объект имеет тип, указанный интерфейсом; это все еще"is-a" отношения. Если автомобиль реализован Fillable, автомобиль "is-a" Fillable, и может использоваться в вашем коде, где бы вы ни использовали Fillable.

состав принципиально отличается от наследования. когда вы используете композицию, вы (как и другие ответы) делаете"has-a" отношения между двумя объектами, в отличие от "is-a" отношения, которые вы делаете, когда используете наследование.

Итак, из примеров автомобилей в другом вопросы, если бы я хотел сказать, что автомобиль"has-a" бензобак, я бы использовал состав, следующим образом:

public class Car {

private GasTank myCarsGasTank;

}

надеюсь, это прояснит любое недоразумение.


наследование выводит IS-A отношения. состав выводит имеет-отношение. Statergy pattern объясняет, что композиция должна использоваться в случаях, когда есть семейства алгоритмов, определяющих конкретное поведение.
классический пример класса duck, который реализует поведение мухи.

public interface Flyable{
     public void fly();
}

public class Duck {
Flyable fly;

 public Duck(){
  fly=new BackwardFlying();
 }

}

таким образом, мы можем иметь несколько классов, которые реализуют полет например:

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");
 }
}

если бы это было для наследования у нас было бы два разных класса птиц, которые реализуют функцию fly снова и снова.таким образом, наследование и состав совершенно различны.


композиция так же, как это звучит - вы создаете объект путем подключения частей.

редактировать остальная часть этого ответа ошибочно основана на следующей предпосылке.
Это достигается с помощью интерфейсов.
Например, используя Car пример выше,

Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel

таким образом, с помощью нескольких стандартных теоретических компонентов вы можете создать свой объект. Это ваша работа, чтобы заполнить как House защищает своих оккупантов, и как a Car защищает своих пассажиров.

наследование, как и наоборот. Вы начинаете с полного (или неполного) объекта и заменяете или переопределяете различные биты, которые хотите изменить.

например, MotorVehicle С Fuelable способ и Drive метод. Вы можете оставить метод топлива как есть, потому что это то же самое, чтобы заполнить мотоцикл и автомобиль, но вы можете переопределить Drive метод, потому что мотоцикл ездит по-разному к Car.

с наследованием некоторые классы уже полностью реализованы, а другие имеют методы, которые вы вынуждены переопределить. С композицией тебе ничего не дается. (но вы можете реализовать интерфейсы, вызвав методы в других классах, если у вас есть что-то лежащее).

композиция рассматривается как более гибкая, потому что если у вас есть такой метод, как iUsesFuel, вы можете иметь метод где-то еще (другой класс, другой проект), который просто беспокоится о работе с объектами, которые могут быть заправлены, независимо от того, является ли это автомобиль, лодка, плита, барбекю и т. д. Мандат интерфейсы, классы, которые говорят, что они реализуют этот интерфейс на самом деле есть методы, что интерфейс-это все. Например,

iFuelable Interface:
   void AddSomeFuel()
   void UseSomeFuel()
   int  percentageFull()

тогда у вас может быть метод где-то еще

private void FillHerUp(iFuelable : objectToFill) {

   Do while (objectToFill.percentageFull() <= 100)  {

        objectToFill.AddSomeFuel();
   }

странный пример, но он показывает, что этот метод не заботится о том, что он заполняет, потому что объект реализует iUsesFuel, это можно заполнить. Конец истории.

если бы вы использовали наследование вместо этого, вам понадобилось бы другое FillHerUp методы борьбы с MotorVehicles и Barbecues, если у вас не было довольно странного "ObjectThatUsesFuel" базовый объект, от которого наследовать.


в качестве другого примера рассмотрим класс автомобиля, это будет хорошее использование композиции, автомобиль будет "иметь" двигатель, трансмиссию, шины, сиденья и т. д. Ни один из этих классов не будет расширен.


состав наследства и то же?

Они не то же самое.

состав: он позволяет обрабатывать группу объектов так же, как и один экземпляр объекта. Цель композита - "составить" объекты в древовидные структуры для представляют часть-целые иерархии

наследование: класс наследует поля и методы у всех свои суперклассы, прямые или косвенные. Подкласс может переопределять методы, которые он наследует, или скрывать поля или методы, которые он наследует.

Если я хочу реализовать шаблон композиции, как я могу это сделать на Java?

Википедия статья достаточно хороша для реализации составного шаблона в java.

enter image description here

ключ Участники:

компонент:

  1. является абстракцией для всех компонентов, включая составные
  2. объявляет интерфейс для объектов в состав

лист:

  1. представляет листовые объекты в состав
  2. реализует все компонент методы

композитные:

  1. представляет собой составной компонент (компонент, имеющих детей)
  2. реализует методы манипулирования детьми
  3. реализует все методы компонентов, как правило, делегируя их своим дочерним элементам

пример кода для понимания композитные выкройка:

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());
    }

}

выход:

Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0

объяснение:

  1. часть лист
  2. автомобиль содержит много деталей
  3. разные частей из автомобиля были добавлены в автомобиль
  4. цена автомобиль = сумма ( цена каждого часть )

см. ниже вопрос для плюсов и минусов состава и наследования.

предпочитайте композицию наследованию?


наследование между двумя классами, когда один класс расширяет другой класс определяет " - ЭТО" отношения.

состав на другом конце содержит экземпляр другого класса в классе устанавливается "Есть" отношения. состав в java полезно, Так как это технически облегчает множественное наследование.


в простом слове средство агрегации имеет отношение ..

композиция является частным случаем агрегации. В более конкретном случае ограниченная агрегация называется композицией. Когда объект содержит другой объект, если содержащийся объект не может существовать без существования объекта-контейнера, то он называется композицией. пример: класс студентов содержит. Ученик не может существовать без класса. Существует композиция между классом и студентами.

Зачем Использовать Агрегацию

Возможность Повторного Использования Кода

При Использовании Агрегации

повторное использование кода также лучше всего достигается путем агрегации, когда нет отношения ship

наследование

наследование является родительским дочерним отношением наследование означает отношение

наследование в java является механизм, с помощью которого один объект приобретает все свойства и поведение родительского объекта.

использование наследования в Java 1 Возможность Повторного Использования Кода. 2 добавьте дополнительную функцию в дочерний класс, а также переопределение метода (таким образом, может быть достигнут полиморфизм времени выполнения).


композиция-это когда что-то состоит из отдельных частей, и оно имеет сильную связь с этими частями. Если основная часть умирает так же, как и другие, они не могут жить своей собственной жизнью. Грубый пример-человеческое тело. Вынуть сердце и все остальные части отмирают.

наследование-это когда вы просто берете то, что уже существует, и используете его. Нет никаких прочных отношений. Человек может унаследовать имущество отца, но может обойтись и без него.

Я не знаю Java, поэтому я не могу привести пример, но я могу предоставить объяснение понятий.


хотя оба наследства и состав обеспечивает reusablility код, основное различие между составом и наследование в Java заключается в том, что состав позволяет повторно использовать код без его продления, но по наследству вы должны расширить класс для повторного использования кода или функции. Еще одно отличие от этого заключается в том, что с помощью Composition можно повторно использовать код даже для конечного класса, который не является расширяемым, но наследование не может повторно использовать код в таких случаях. Также с помощью Композиция вы можете повторно использовать код из многих классов, поскольку они объявлены как переменная-член, но с наследованием вы можете повторно использовать код только одного класса, потому что в Java вы можете расширить только один класс, потому что множественное наследование не поддерживается в Java. Вы можете сделать это в C++, хотя, потому что там один класс может расширить более одного класса. Кстати, вы всегда должны предпочитайте композицию наследованию в Java, это не только я, но даже Джошуа Блох предложил в своей книге


Я думаю, что этот пример ясно объясняет различия между наследование и состав.

в этом примере проблема решается с помощью наследования и композиции. Автор обращает внимание на то, что ; в наследование, изменение суперкласса может вызвать проблемы в производном классе, которые наследуют его.

там вы также можете увидеть разницу в представлении, когда вы используете UML для наследования или состав.

http://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition--which-one-should-you-choose-.html


Состав Наследства Против.

наследования и композиция используются для повторного использования и расширения поведения класса.

наследования в основном используются в модели программирования семейного алгоритма, такой как IS-тип отношения означает аналогичный объект. Образец.

  1. Duster-это автомобиль
  2. сафари-автомобиль

эти принадлежат к семье автомобиля.

композиция представляет собой HAS-A тип отношений.Он показывает способность объекта , такого как Duster имеет пять передач, Safari имеет четыре передачи и т. д. Всякий раз, когда нам нужно расширить возможности существующего класса, используйте композицию.пример нам нужно добавить еще одну шестерню в объект Duster, затем мы должны создать еще один объект gear и составить его в объект duster.

мы не должны вносить изменения в базовый класс, пока / если все производные классы не нуждаются в этих функциях.Для этого сценария мы должны используйте композицию.Такие как

класс A, производный от класса B

класс A, производный от класса C

класс A, производный от класса D.

когда мы добавляем какую-либо функциональность в классе A, она доступна для всех подклассов, даже если класс C и D не требует этих функций.Для этого сценария нам нужно создать отдельный класс для этих функций и составить его в требуемый класс(Вот класс B).

ниже пример:

          // 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");
                       }
                   }

композиция означает создание объекта для класса, который имеет отношение к этому конкретному классу. Предположим, студент имеет отношение к счетам;

наследование, это предыдущий класс с расширенной функцией. Это означает, что этот новый класс является старым классом с некоторой расширенной функцией. Предположим, студент есть студент, но все студенты-люди. Так возникают отношения со студентом и человеком. Это наследство.


нет, оба разные . Композиция следует за отношениями" имеет-а", а наследование следует за отношениями" есть-а". Лучшим примером для композиции была стратегическая модель .


наследование означает повторное использование полной функциональности класса, здесь мой класс должен использовать все методы суперкласса, и мой класс будет тительно связан с суперклассом, и код будет дублироваться в обоих классах в случае наследования.

но мы можем преодолеть все эти проблемы, когда мы используем состав, чтобы поговорить с другим классом . композиция объявляет атрибут другого класса в мой класс, с которым мы хотим поговорить. и какую функциональность мы хотите от этого класса, который мы можем получить, используя этот атрибут.