Наследование по сравнению с [закрытым] агрегированием

В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.

При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.

Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».

Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this. Возьмем этот пример:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

И в другом месте вашего кода:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference и otherReference оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.

142
задан casperOne 30 August 2012 в 19:27
поделиться

11 ответов

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

В 'нормальных' случаях простого вопроса достаточно, чтобы узнать, нужны ли нам наследование или агрегирование.

  • , Если новый класс более или менее как исходный класс. Используйте наследование. Новый класс является теперь подклассом исходного класса.
  • , Если новый класс должен , имеют исходный класс. Используйте агрегирование. Новый класс имеет теперь исходный класс как участника.

Однако существует большая серая область. Таким образом, нам нужны несколько других приемов.

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

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

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

Позволяет, добавляет пример. У нас есть класс 'Собака' с методами: 'Поешьте', 'Обход', 'Лай', 'Игра'.

class Dog
  Eat;
  Walk;
  Bark;
  Play;
end;

Нам теперь нужен класс 'CAT', который потребности 'Едят', 'Обход', 'Мурлыканье' и 'Игра'. Поэтому первая попытка расширить его от Собаки.

class Cat is Dog
  Purr; 
end;

Взгляды, хорошо, но ожидают. Эта кошка может Лаять (Любители кошек уничтожат меня для этого). И лающая кошка нарушает принципы вселенной. Таким образом, мы должны переопределить метод Лая так, чтобы он ничего не делал.

class Cat is Dog
  Purr; 
  Bark = null;
end;

хорошо, это работает, но это плохо пахнет. Так позволяет, пробуют агрегирование:

class Cat
  has Dog;
  Eat = Dog.Eat;
  Walk = Dog.Walk;
  Play = Dog.Play;
  Purr;
end;

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

class Pet
  Eat;
  Walk;
  Play;
end;

class Dog is Pet
  Bark;
end;

class Cat is Pet
  Purr;
end;

Это намного более чисто. Никакие внутренние собаки. И кошки и собаки на том же уровне. Мы можем даже представить других домашних животных для расширения модели. Если это не рыба или что-то, что не идет. В этом случае мы снова должны осуществить рефакторинг. Но это - что-то в течение другого времени.

171
ответ дан 23 November 2019 в 23:05
поделиться

Различие обычно выражается, как различие между "", и "имеет a". Наследование, "является" отношениями, подведен итог приятно в принцип замены Лисков . Агрегирование, "имеет" отношения, просто, что - оно показывает, что агрегирующийся объект имеет один из агрегированных объектов.

Дальнейшие различия существуют также - частное наследование в C++ указывает, "реализован с точки зрения" отношений, которые могут также быть смоделированы агрегированием (невыставленных) членских объектов также.

26
ответ дан 23 November 2019 в 23:05
поделиться

Вот мой наиболее распространенный аргумент:

В любой объектно-ориентированной системе, существует две части к любому классу:

  1. интерфейс : "общественность сталкивается" объекта. Это - набор возможностей, о которых он объявляет остальной части мира. На большом количестве языков набор четко определен в "класс". Обычно это сигнатуры методов объекта, хотя он варьируется немного языком.

  2. реализация : "негласно" работают, который объект делает, чтобы удовлетворить его интерфейс и обеспечить функциональность. Это обычно - код и членские данные объекта.

Один из основных принципов ООП - то, что реализация , инкапсулировал (ie:hidden) в классе; единственной вещью, которую должны видеть посторонние, является интерфейс.

, Когда подкласс наследовался подклассу, он обычно наследовался и реализация и интерфейс. Это, в свою очередь, означает, что Вы , вынудил принять обоих как ограничения на Ваш класс.

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

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

14
ответ дан 23 November 2019 в 23:05
поделиться

Я вижу, что много из "-по сравнению с, имеет - a; они - концептуально различные" ответы на этом и связанных вопросах.

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

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

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

Так, у Вас есть идеальный шторм аргументов против наследования каждый раз, когда необходимо выбрать один или другой:

  1. Вашим выбором, вероятно, будет неправильный в какой-то момент
  2. Изменение, что выбор является трудным, после того как Вы сделали его.
  3. Наследование имеет тенденцию быть худшим выбором, поскольку оно больше ограничивает.

Таким образом, я склонен выбирать агрегирование - даже когда, кажется, существует сильное, - отношения.

6
ответ дан 23 November 2019 в 23:05
поделиться

Я дал ответ на , "" По сравнению с, "Имеет a": какой лучше? .

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

имеет смысл для Вашего производного класса иметь все методы суперкласса? Или Вы просто бесшумно обещаете себе, что те методы должны быть проигнорированы в производном классе? Или Вы находите себя методами переопределения от суперкласса, делая их без операций в секунду, таким образом, никто не называет их непреднамеренно? Или давая подсказки Вашему инструменту поколения документа API для исключения метода из документа?

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

11
ответ дан 23 November 2019 в 23:05
поделиться

В начале GOF они заявляют

состав объекта Пользы по наследованию классов.

Это далее обсуждено здесь

36
ответ дан 23 November 2019 в 23:05
поделиться

Вопрос обычно формулируется как Состав по сравнению с Наследованием , и это спросили здесь прежде.

3
ответ дан 23 November 2019 в 23:05
поделиться

Я думаю, что это не альтернативные дебаты. Это просто что:

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

у Обоих есть их место, но наследование более опасно.

, Хотя, конечно, не имело бы смысла иметь класс Форма, 'имеющая -' Точка и Квадратные классы. Здесь наследование должно.

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

2
ответ дан 23 November 2019 в 23:05
поделиться

Я хотел сделать это комментарием к исходному вопросу, но 300 укусам символов [; <).

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

кроме того, я предполагаю, что ценно не перепутать цель с инструментом. Каждый хочет удостовериться, что выбранная техника или методология поддерживают достижение главной цели, но я не делаю вещи which-technique-is-best обсуждение, из контекста очень полезно. Это действительно помогает знать ловушки разных подходов наряду с их ясными зонами наилучшего восприятия.

, Например, что отсутствует Вы для выполнения, что Вы имеете в наличии для начала, и каковы ограничения?

Вы создающий платформу компонента, даже особое назначение один? Действительно ли интерфейсы отделимы от реализаций в системе программирования, или она выполняется практикой с помощью другого вида технологии? Можно ли разделить структуру наследования интерфейсов (если таковые имеются) от структуры наследования классов, которые реализуют их? Действительно ли важно скрыть структуру класса реализации из кода, который полагается на интерфейсы, которые поставляет реализация? Там несколько реализаций должны быть применимыми одновременно, или действительно ли изменение является большим количеством сверхурочного времени в результате обслуживания и улучшения? Это и больше потребностей, которые рассмотрят перед фиксацией на инструменте или методологии.

Наконец, это настолько важный для блокировки различий в абстракции и как Вы думаете о нем (как в - по сравнению с, имеет-) к различным функциям технологии OO? Возможно, так, если это сохраняет концептуальную структуру последовательной и управляемой для Вас и других. Но мудро не быть порабощенным этим и искривлениями, которые Вы могли бы закончить тем, что делали. Возможно, лучше отступить уровень и не быть настолько твердым (но оставить хорошее повествование, таким образом, другие могут сказать то, что произошло). [Я ищу то, что делает конкретную часть программы объяснимой, но несколько раз я иду для элегантности, когда существует большая победа. Не всегда лучшая идея.]

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

3
ответ дан 23 November 2019 в 23:05
поделиться

Я покрою where-these-might-apply часть. Вот пример обоих в игровом сценарии. Предположим, существует игра, которая имеет различные типы солдат. У каждого солдата может быть ранец, который может содержать разные вещи.

Наследование здесь? существует морской, зеленый берет & снайпер. Это типы солдат. Так, существует Солдат базового класса с морским, Зеленым Беретом & Снайпер как производные классы

Агрегирование здесь? ранец может содержать гранаты, оружие (различные типы), нож, medikit, и т.д. Солдат может быть снабжен любым из них в любом данном моменте времени, плюс у него может также быть пуленепробиваемый жилет, который действует как броня при нападении и его травма уменьшается к определенному проценту. Класс солдата содержит объект пуленепробиваемого класса жилета и класса ранца, который содержит ссылки на эти объекты.

1
ответ дан 23 November 2019 в 23:05
поделиться

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

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

0
ответ дан 23 November 2019 в 23:05
поделиться
Другие вопросы по тегам:

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