Состав против делегирования

Есть ли разница с точки зрения реализации, чем дизайн композиции может отличаться от делегирования. Например, приведенный ниже код выполняет делегирование, поскольку пользователь не может получить доступ к составному объекту (то есть «а») без использования b. Следовательно, пользователю нужно будет вызывать интерфейсы класса b, а затем «класс b» вызывать соответствующие интерфейсы «класса a», выполняя делегирование. Имеет ли это смысл ?

Class A {
friend class B;
private: 
A(){}; //dont want user to instantiate this class object since it wont sense without any context. Just like a room with no house.
void PrintStructure(){};
};

Class B{
public:
void PrintStructure(){a.PrintStructure();} //delegate

private:
A a; //composition
};

person Frank Q.    schedule 26.01.2010    source источник


Ответы (3)


Термин «композиция» обычно используется в терминах объектного моделирования как выражение отношения «имеет-а» и является формой ассоциации (еще одна форма агрегации). Это обычно противопоставляется «наследованию» («является» отношением). Так:

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

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

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

Вы заметите, что и A, и B из вашего примера имеют один и тот же внешний интерфейс. Чаще всего делают что-то вроде этого:

// this represents an interface
class A {
public:
  virtual void printStructure() = 0;
}

с конкретными классами:

class ConcreteA : A {
public:
  virtual void printStructure() { ... }
}

и

class DelegateA : A {
public:
  DelegateA(A& a) { this.a = a; }
  virtual void printStructure() { a.printStructure(); }
private:
  A a;
}

Извините за мои, вероятно, синтаксические ошибки C++. Я немного ржавый.

person cletus    schedule 26.01.2010
comment
Если композиция подразумевает, что дочерний элемент не может существовать без контекста родителя, то следует ли пользователю никогда не разрешать создавать объект составного класса? Например, мой усовершенствованный, например, будет класс A { друг класса B; частный: A () {}; недействительным PrintStructure () {}; }; Класс B{ public: void PrintStructure(){a.PrintStructure();} // делегировать private: A a; //сочинение }; Теперь класс B имеет класс A. Пользователь должен использовать только интерфейсы класса B для изменения поведения класса A, а класс B должен делегировать такие задачи функциям класса A. Хорош ли этот дизайн? - person Frank Q.; 26.01.2010
comment
@Frank: Классы друзей - это один из способов реализовать такие отношения. Хотя они мне не нравятся. Более элегантное решение состоит в том, чтобы конструктор Room требовал экземпляра House, который затем становится его родителем. - person cletus; 26.01.2010
comment
Как бы вы закодировали что-то подобное в моем примере? Более того, я не хочу, чтобы пользователь мог создавать экземпляр объекта A, поскольку не имеет смысла выполнять какие-либо операции над A без контекста B. - person Frank Q.; 26.01.2010
comment
@Frank: моя версия A имеет чисто виртуальную функцию. Это не может быть создано. - person cletus; 27.01.2010
comment
хороший пример, перевел ваш ответ на португальский язык; blog.renatogama.com/2012/05/agregacao-e-composicao спасибо - person Renato Gama; 11.05.2012

Я вижу пару отличий:

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

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

person Michael Ekstrand    schedule 26.01.2010
comment
Экспорт методов не требуется для делегирования. Из Википедии: в своем первоначальном использовании делегирование относится к одному объекту, полагающемуся на другой для предоставления определенного набора функций. - person danben; 26.01.2010

Композиция связана с отношениями между объектами.

Делегирование — это передача работы от одного объекта к другому.

На самом деле это разные (но иногда связанные) проблемы.

У вас есть B, составленный из A (B относится к A). B также делегирует один из своих методов A.

Но так как использование B пользователем A является частным (полностью инкапсулированным в черном ящике B), я бы не назвал использование B A «композицией». Я бы использовал «композицию» только в том случае, если к классу A можно было бы получить доступ из B. Здесь важно, если логическая модель B «имеет» A.

В вашем случае B реализован с точки зрения A. Поскольку это проблема реализации, ее можно рассматривать как не часть логической модели B. То есть вы можете разумно говорить о Б, не говоря и не заботясь об А.

Тем не менее, этот материал действительно важен только для инструментов моделирования PHB и UML. Или, возможно, если вы изучаете шаблоны проектирования. Я бы не стал слишком зацикливаться на этом.

[PHB => Островолосый босс]

person rickmode    schedule 26.01.2010
comment
Означает ли это, что в композиции составной объект (в данном случае а) должен быть обнародован? Таким образом, пользователь получит доступ к a, используя b, например, B b; b.a.PrintStructure(); // предполагается, что функция-член является общедоступной. - person Frank Q.; 26.01.2010
comment
Здесь нет абсолютно правильного или неправильного. Важна цель занятий. Вы не должны делать член класса B общедоступным только из-за некоторого понятия композиции. Лучше подумайте, важно ли a для кода, использующего экземпляр класса B. Если коду, использующему B, необходимо добраться до a, то должен быть способ (метод) для B для доступа к нему. В вашем примере a является закрытым, поэтому его существование и использование в B полностью скрыто от кода, использующего класс B. Обычно это хорошо. Подробнее: en.wikipedia.org/wiki/Information_hiding en.wikipedia.org/wiki/Object_composition - person rickmode; 26.01.2010
comment
Спасибо, я начал другую ветку, если возврат ссылки на частный член в композиции нарушает ООП. В моем случае B должен иметь A, и все же пользователю необходимо установить некоторые свойства A, которые потребуют от него/нее какого-либо способа добраться до A. Я также не хочу использовать делегирование, которое потребовало бы от меня предоставления методов в B для каждого метода. в. - person Frank Q.; 26.01.2010