Агрегация или состав: у меня есть пример кода [duplicate]

Строка ошибки «Ссылка на объект, не установленная на экземпляр объекта.» указывает, что вы не назначили экземпляр объекта объектной ссылке, и все же вы получаете доступ к свойствам / методам этого объекта.

например: скажем, у вас есть класс под названием myClass и он содержит одно свойство prop1.

public Class myClass
{
   public int prop1 {get;set;}
}

Теперь вы получаете доступ к этому prop1 в каком-то другом классе, как показано ниже:

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref.prop1 = 1;  //This line throws error
     }
}

выше строки выдает ошибку, потому что ссылка класса myClass объявлена, но не создана, или экземпляр объекта не назначается referecne этого класса.

Чтобы исправить это, вам нужно создать экземпляр (присвоить объект ссылке на этот класс).

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref = new myClass();
        ref.prop1 = 1;  
     }
}
150
задан Péter Török 28 June 2010 в 16:38
поделиться

15 ответов

Они совершенно разные. Наследование - это отношение "is-a" . Композиция представляет собой «has-a» .

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

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

Я очень рекомендую книгу Джоша Блоха Эффективная Java 2-е издание

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

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


См. Также:

234
ответ дан polygenelubricants 27 August 2018 в 05:23
поделиться
  • 1
    это отличная помощь – Sikander 4 May 2013 в 21:49
  • 2
    Интересно. Почему бы просто не создать новый класс java.util.Stack2, который использует композицию? – qed 7 November 2014 в 14:37
  • 3
    Я ценю этот ответ; тем не менее, я чувствую, что ответ выходит из-под контроля и больше вникает в проблемы, связанные с дизайном языка (и конкретного пакета), чем он отвечает на заданный вопрос о композиции против наследования. Я большой поклонник ответа на вопрос о SO, ссылаясь на ресурсы - не ссылаясь на внешние ресурсы, не предоставляя более подробное резюме, чем однострочное суммирование. – Thomas 23 January 2015 в 15:09
  • 4
    танк ты отличный ответ – Hosseini 16 May 2016 в 07:24
  • 5
    Плохой пример, я должен был сделать дополнительный поиск, чтобы понять, что такое Vector и Stack. – Sam Ramezanli 25 March 2017 в 17:30

Элементы композиции 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.
}
150
ответ дан Andrea Bergonzo 27 August 2018 в 05:23
поделиться
  • 1
    Я бы изменил «автомобиль». к "приведенному в действие транспортному средству" как и во многих интертратациях, автомобили и автомобили эквивалентны. – Andrey Akhmetov 25 November 2013 в 00:02
  • 2
    @hexafraction Я согласен с тем, что автомобиль, скорее всего, будет лучшим выбором, но в то же время -codaddict-проиллюстрировал точку просто отлично для того, что было задано. – nckbrz 27 March 2014 в 19:46
  • 3
    Этот пример действительно полезен. – user2180794 9 May 2016 в 02:05
  • 4
    "Двигатель" :-/ – Omar Tariq 14 December 2016 в 11:32
  • 5
    Это лучший ответ! – Melchia 1 February 2018 в 09:53

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

4
ответ дан BlackICE 27 August 2018 в 05:23
поделиться

Являются ли композиция и наследование одинаковыми?

Они не совпадают.

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

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

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

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

Ключевые участники:

Компонент:

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

Лист:

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

Композит:

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

Пример кода для понимания Composite patter n:

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. Цена Автомобиль = сумма (Цена каждой партии)

См. ниже вопрос о преимуществах и недостатках композиции и наследования.

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

4
ответ дан Community 27 August 2018 в 05:23
поделиться
  • 1
    Имеет ли смысл внедрять детали для класса автомобилей. Не будет ли это хорошо, если вы будете использовать его в качестве композиции – bhalkian 20 March 2018 в 05:09

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

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

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

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

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

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

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

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

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

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

private void FillHerUp(iFuelable : objectToFill) {

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

        objectToFill.AddSomeFuel();
   }

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

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

7
ответ дан dlamblin 27 August 2018 в 05:23
поделиться
  • 1
    В соглашениях Java указано, что имена классов и интерфейсов записаны в ThisCase, а не в camelCase. Поэтому лучше всего назвать ваши интерфейсы IDrivable и т. Д. Возможно, вам не понадобится «I». если вы правильно перегруппируете все свои интерфейсы в пакет. – ThePyroEagle 21 December 2015 в 11:15

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

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

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

14
ответ дан frictionlesspulley 27 August 2018 в 05:23
поделиться

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

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

0
ответ дан HM Nayem 27 August 2018 в 05:23
поделиться

В «Агрегации простого слова» означает «Отношения».

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

Зачем использовать Aggregation

Повторное использование кода

Когда использование агрегирования

Повторное использование кода также наилучшим образом достигается путем агрегирования, когда нет Относительный корабль

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

Наследование является родительским отношением к дочерним отношениям, связанным с отношением. RelationShip

Наследование в Java - это механизм, в котором один объект приобретает все свойства и поведение родительского объекта.

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

3
ответ дан Keshav Gera 27 August 2018 в 05:23
поделиться
  • 1
    голосовать + за полиморфизм во время выполнения – manfromnowhere 12 December 2017 в 08:46

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

2
ответ дан Nitin Pawar 27 August 2018 в 05:23
поделиться

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

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

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

В классе Test с использованием r reference Я могу вызывать методы класса X, а также класс Y. Эта гибкость никогда не существовала в наследовании

3) Еще одно большое преимущество: Unit testing

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, а наследование также известно как отношение IS-A

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

17
ответ дан Radim Köhler 27 August 2018 в 05:23
поделиться

Нет, оба они разные. Композиция соответствует отношениям «HAS-A» и наследованию следуют отношения «IS-A». Лучшим примером для композиции был стратегический паттерн.

0
ответ дан Ranga Reddy 27 August 2018 в 05:23
поделиться
  • 1
    Его единственное качество комментариев – Billa 24 December 2017 в 18:51
  • 2
    Вы просто прокомментировали то же самое, что принятый ответ сказал за 7 лет до вас? – Anjil Dhamala 9 February 2018 в 15:52

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

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

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

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

16
ответ дан Ravindra babu 27 August 2018 в 05:23
поделиться
  • 1
    большой ответ и разъяснение. – StackOverflowed 15 September 2012 в 23:38
  • 2
    Ссылка только ответы обескуражены, потому что они устаревают. Пожалуйста, укажите, по крайней мере, самую важную релевантную информацию из ссылки в вашем ответе. – Okuma.Scott 18 March 2014 в 14:17

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

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

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

2
ответ дан Robert Rocha 27 August 2018 в 05:23
поделиться

Наследование Vs Состав.

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

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

  1. Duster - автомобиль
  2. Safari - это автомобиль

. Они принадлежат семейству Car.

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

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

класс A Производится классом B

Класс A Производится классом C

Класс A Производится классом D.

Когда мы добавляем какие-либо функциональные возможности в класс А, тогда он доступен для всех подклассов, даже если классам 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");
                       }
                   }
1
ответ дан Sheo Dayal Singh 27 August 2018 в 05:23
поделиться

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

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

0
ответ дан Vikas Kapadiya 27 August 2018 в 05:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: