аггрегирование против расширения
От: Аноним  
Дата: 18.01.05 10:56
Оценка:
в чем собственно принципиальная разница?
в каких случаях что лучше использовать?
Re: аггрегирование против расширения
От: A_Gura Россия http://a-gura.livejournal.com
Дата: 18.01.05 11:10
Оценка: 1 (1)
Здравствуйте, <Аноним>, Вы писали:

А>в чем собственно принципиальная разница?


Расширение — это прямое наследование. Такоим образом ты получаешь такие преимущества как полиморфизм, позднее связывание и наследование базовой функциональности. Аггрегирование — это включение объектов в состав другого объекта.
Вообще говоря, время жизни аггрегированного объекта, равно времени жизни аггрегата (объекта-владельца)

А>в каких случаях что лучше использовать?


Соответственно, наследование используем для представления связи типа родитель-потомок (вид-подвид и т.д.). Аггрегирование используем для представления связей типа целое-часть.
... << RSDN@Home 1.1.4 @@subversion >>
Работать надо над собой...
Re: аггрегирование против расширения
От: dshe  
Дата: 18.01.05 11:28
Оценка:
Здравствуйте, Аноним, Вы писали:

А>в чем собственно принципиальная разница?

А>в каких случаях что лучше использовать?

Это не совсем ответ на твой вопрос, но раз уж речь пошла о наследовании, будет полезно почитать Why extends is evil.
--
Дмитро
Re: аггрегирование против расширения
От: Beard-electronic Россия  
Дата: 18.01.05 13:12
Оценка:
Здравствуйте, Аноним, Вы писали:

А>в чем собственно принципиальная разница?

А>в каких случаях что лучше использовать?

Про разницу уже сказали (наследование и отношение "целое-часть").
А что и когда лучше использовать — вопрос во многих случаях спорный.
Можно посмотреть классиков — "Design patterns" например.
Re[2]: аггрегирование против расширения
От: nant Россия  
Дата: 19.01.05 12:11
Оценка: 2 (1)
А>>в чем собственно принципиальная разница?

A_G>Расширение — это прямое наследование. Такоим образом ты получаешь такие преимущества как полиморфизм, позднее связывание и наследование базовой функциональности.


A_G>Аггрегирование — это включение объектов в состав другого объекта.

A_G>Вообще говоря, время жизни аггрегированного объекта, равно времени жизни аггрегата (объекта-владельца)
Вообще говоря нет — различают два вида аггрегации: собственно аггрегацию и композицию.
Все начинается с ассоциации, которая говорит о том, что между объектами двух классов можно построить некоторое отношение.
Различают отношения 1->1 (один к одному), 1->N (один ко многим) и N->M (многие ко многим). Ассоциация как правило реализуется через ссылку на объект или через коллекцию.
Аггрегация является частным случаем ассоциации, при котором имеет место отношение "часть-целое" (то самое включение объектов в состав другого объекта), композиция — аггрегация, при которой композит несет отвественность за хранение и жизненный цикл аггрегированного объекта.
Пример ответственности за хранение: при хранении в памяти в аггрегате хранится только ссылка на аггрегированный объект, а в композите — собственно содержимое аггрегированного объекта. Пример синтетический, в том или ином виде реализуется для старых компиляторов С++.Отсюда, также, растет странное поведение Rational Rose, где для создания композиции нужно создать аггрегацию (здесь все верно) и установить вместо хранения по ссылке хранение по значению (что, собственно говоря, уже неверно, т.к. в той же Java не бывает хранения по значению).

Аггрегация допускает построение отношений N->M, когда как композиция — только 1->N (иначе нельзя соблюсти ограничение на время жизни аггрегированного объекта).

Данное описание изложено в спецификации OMG UML. Сообщение надо расценивать исключительно как терминологическое уточнение .
Re: аггрегирование против расширения
От: nant Россия  
Дата: 19.01.05 12:44
Оценка: 14 (4)
Здравствуйте, Аноним, Вы писали:

А>в чем собственно принципиальная разница?

А>в каких случаях что лучше использовать?
Ниже я буду называть расширение наследованием (это более

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

Для получения хорошего дизайна необходимо, чтобы выполнялся принцип подстановки, сформулированный Барбарой Лисков (Liskov Substitution Principle, LSP), который гласит, что S является подклассом T только тогда, когда любые программы, написанные с использованием объектов класса T будут иметь то же самое поведение, если все объекты класса T заменить объектами класса S.

Хрестоматийным примером неоправданного наследования стали квадрат и прямоугольник:
Рассмотрим класс прямоугольника со следующим контрактом:
class Rectangle()
{
   private int w;
   private int h;
   
   public Rectangle(int w, int h)
   {
       setWidth(w);
       setHeight(h);
   }

   public int getWidth()
   {
       return w;
   }

   public int getHeight()
   {
       return h;
   }

   public void setHeight(int h)
   {
       this.h = h;
   }

   public void setWidth(int w)
   {
       this.w = w;
   }

   
}


Затем создадим класс Square, как прямоугольник с равными сторонами. Кроме создания специяического конструктора нам нужно будет перегрузить методы setWidth и setHeight с тем, чтобы ыполнялось правило w == h.

class Square
{
   public Square (int a)
   {
       super(a,a);  
   }
   public void setHeight(int h)
   {
       super.setHeight(h);
       super.setWidth(h);
   }

   public void setWidth(int w)
   {
       super.setHeight(w);
       super.setWidth(w);
   }

}


Казалось бы все замечательно, но представим себе следующий тест:

public class SquareTest
{

   public void doTest(Rectangle r)
   {
      r.setWidth(5);
      r.setHeight(6);
      if (30 != r.getWidth()*r.getHeight())
      {
         throw new RuntimeException("Square test failed");
      }   
   }

}


Из которого видно, что наследование здесь неправомерно (тест сломается для экземпляра класса Square). Продобное применение наследования ведет к соверженно неоправданному использованию reflection (в т.ч. instanceof). Поэтому с наследованием нужно обращаться очень осторожно — оно является поведенческим отношением, а не какой-то общностью, взятой из реального мира. К примеру можно построить такой поведенческий контракт прямоугольника, при котором квадрат будет являться прямоугольником (например, выбросив методы setWidth и setHeight из класса Rectangle), но в приведенном случае Square не должен быть наследником Rectangle.



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

2) Если нужно в нескольких классах получить какой-то базовый набор полей (главным образом) и алгоритмов (читай — protected методов). Но и в этом случае стоит пользоваться наследованием до тех пор, пока возможно наследование базового набора путем наследования класса с пакетной видимостью. Т.е. все прямые пользователи базыклассы первого уровня (e .g. наследники java.lang.Object), использующие тот самый общий набор полей и алгортимов, — лежат в одном пакете. (В с++ в таких случаях стоит использовать protected и private наследование).
Если это не так, то зачастую бывает правильнее скопировать этот базовый набор по числу пакетов, где лежат прямые пользователи базы. По моему опыту неправильное наследование обходится в поддержке дороже, чем дублирование идентичного кода по пакетам.

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

Основное правило — если между классами нет поведенческой общности — лучше использовать аггрегацию и иногда даже дублирование кода (!), потому как при правильном подходе к дублированию, оно будет менее болезненным, чем неправомерное наследование.


Плюсы наследования изложил
Автор: A_Gura
Дата: 18.01.05
A_Gura

Также, насколько я понимаю, в статье на которую дал ссылку
Автор: dshe
Дата: 18.01.05
dshe изложены схожие соображения.
Re: аггрегирование против расширения
От: khazzar Россия  
Дата: 19.01.05 13:21
Оценка:
Здравствуйте, Аноним, Вы писали:

А>в чем собственно принципиальная разница?

А>в каких случаях что лучше использовать?

указываемое выше применение агрегации для реализации отношения "часть целого", на мой взгляд, является его прямым применением агрегации и рассматривать в данном случае наследование как альтернативу не слишком корректно.
в контексте заданного вопроса и языка java агрегирование бывает полезно для "эмуляции"(=реализации) множественного наследования, как ни странно. кстати, это совсем не отменяет применение интерфейсов
Re[2]: аггрегирование против расширения
От: tavr  
Дата: 20.01.05 15:01
Оценка:
Здравствуйте, nant, Вы писали:

N>Хрестоматийным примером неоправданного наследования стали квадрат и прямоугольник:

в данном примере объекты должны быть неизменяемыми (по аналогии с Integer)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.