Re[7]: [C++] наследование vs агрегация
От: igna Россия  
Дата: 13.05.11 15:22
Оценка: +1
Здравствуйте, Abyx, Вы писали:

A>а о нём никто не знает.


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

A>кроме того someMethodName можно сделать protected


Protected члены относятся к интерфейсу класса. Какой-нибудь другой любитель наследования унаследует от твоего CorvusRegistry; тоже найдет какой-нибудь аргумент в пользу.
Re: [C++] наследование vs агрегация
От: Игoрь Украина  
Дата: 18.05.11 19:03
Оценка: +1
Здравствуйте, Abyx, Вы писали:

Слишком мало контекста, есть ли другие типы реестров? Если нет, то я вообще не вижу смысла в таком разбиении. Забабахать одним классом, да и все. Это если вы привели полный контекст. А так, можно и наследованием. Реализация с агрегирванием мне не нравится.
[C++] наследование vs агрегация
От: Abyx Россия  
Дата: 12.05.11 22:40
Оценка:
есть какая-то задача, например слежение за воронами
надо
1) вести учет ворон,
2) считать суммарное число перьев у ворон одного типа

для этой задачи написан класс который делегирует работу двум другим классам, решающем соответствующие подзадачи
class  PlumesCounter
{
public:
    uint getCount(uint corvusType);
    void changeCount(uint corvusType, int delta);
    void setCount(uint corvusType, uint value);
    void reset();
    bool wasUpdated();
};

class RegistryImpl
{
public:
    RegistryImpl(Counter&);

    void update(uint corvusId, uint corvusType, uint plumeCount);
    void remove(uint corvusId);
    void reset();
    uint tryGetType(uint corvusId);
    uint findAnyOfType(uint corvusType);
};

class CorvusRegistry
{
public:
    CorvusRegistry() : counter(), regImpl(counter) {}

    uint getCount(uint corvusType) { return counter.getCount(corvusType); }
    void changeCount(uint corvusType, int delta) { counter.changeCount(corvusType, delta); }
    void setCount(uint corvusType, uint value); // ... тоже делегирование
    void reset();
    bool wasUpdated();

    void update(uint corvusId, uint corvusType, uint plumeCount) { regImpl.update(corvusId, corvusType, plumeCount); }
    void remove(uint corvusId);
    void reset();
    uint tryGetType(uint corvusId);
    uint findAnyOfType(uint corvusType);

private:
    PlumesCounter counter;
    RegistryImpl regImpl; 
};


я смотрю на это и вижу кучу строк кода от которых можно избавиться.
я хочу заменить агрегацию наследованием чтоб выкинуть "ненужные" строчки кода
struct CorvusRegistry : PlumesCounter, RegistryImpl
{
    CorvusRegistry() { regImpl.setCounter(*this); }
};


прав я или не прав?
In Zen We Trust
Re: [C++] наследование vs агрегация
От: Undying Россия  
Дата: 13.05.11 04:59
Оценка:
Здравствуйте, Abyx, Вы писали:

A>для этой задачи написан класс который делегирует работу двум другим классам, решающем соответствующие подзадачи

A>
A>    uint getCount(uint corvusType) { return counter.getCount(corvusType); }
A>    void changeCount(uint corvusType, int delta) { counter.changeCount(corvusType, delta); }
A>    void setCount(uint corvusType, uint value); // ... тоже делегирование
A>    void reset();
A>    bool wasUpdated();
A>


В чем смысл этого кода? Зачем методы агрегированного класса выставлять в интерфейс основного класса?

A>я смотрю на это и вижу кучу строк кода от которых можно избавиться.


Если просто выставить агрегированный класс в публичный интерфейс основного класса, то дублирование кода исчезнет.
Re: [C++] наследование vs агрегация
От: igna Россия  
Дата: 13.05.11 06:50
Оценка:
Здравствуйте, Abyx, Вы писали:

A>я хочу заменить агрегацию наследованием чтоб выкинуть "ненужные" строчки кода


Без наследования вполне можно обойтись сделав агрегирование видимым для пользователя:

struct CorvusRegistry
{
    CorvusRegistry() { regImpl.setCounter(counter); }

    PlumesCounter counter;
    RegistryImpl regImpl; 
};


Или если религия не позволяет открывать данные, то:

struct CorvusRegistry
{
    CorvusRegistry() { regImpl_.setCounter(counter_); }

    PlumesCounter& counter() { return counter_; }
    RegistryImpl& regImpl() { return regImpl_; }

private:
    PlumesCounter counter_;
    RegistryImpl regImpl_; 
};
Re: [C++] наследование vs агрегация
От: eugene0 Россия  
Дата: 13.05.11 07:56
Оценка:
Здравствуйте, Abyx, Вы писали:

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

Если же хочется объединить PlumesCounter и RegistryImpl чисто внешне, для того, чтобы клиент понял, что оба класса занимаются воронами, можно создать для них общее пространство имен.
Re[2]: [C++] наследование vs агрегация
От: Abyx Россия  
Дата: 13.05.11 09:16
Оценка:
Здравствуйте, Undying, Вы писали:

U>Если просто выставить агрегированный класс в публичный интерфейс основного класса, то дублирование кода исчезнет.


агрегированный класс — это деталь реализации, пользователям класса CorvusRegistry не надо знать с помощью каких классов он работает
In Zen We Trust
Re[2]: [C++] наследование vs агрегация
От: Abyx Россия  
Дата: 13.05.11 09:21
Оценка:
Здравствуйте, igna, Вы писали:

I>Без наследования вполне можно обойтись сделав агрегирование видимым для пользователя:


классы PlumesCounter и RegistryImpl это детали реализации CorvusRegistry, коду использующему CorvusRegistry о них знать не надо

к тому же такое решение нарушает Закон Деметры
In Zen We Trust
Re[2]: [C++] наследование vs агрегация
От: Abyx Россия  
Дата: 13.05.11 09:25
Оценка:
Здравствуйте, eugene0, Вы писали:

E>Непонятно, зачем нужен класс CorvusRegistry в этом примере, если он только и делает, что делегирует все двум классам, которые агрегирует внутри себя.


это фасад.
кроме того он умеет правильно создавать и настраивать PlumesCounter и RegistryImpl
In Zen We Trust
Re[3]: [C++] наследование vs агрегация
От: igna Россия  
Дата: 13.05.11 11:24
Оценка:
Здравствуйте, Abyx, Вы писали:

A>классы PlumesCounter и RegistryImpl это детали реализации CorvusRegistry, коду использующему CorvusRegistry о них знать не надо


Это в полной мере относится и к твоему решению.
Re[3]: [C++] наследование vs агрегация
От: Undying Россия  
Дата: 13.05.11 11:49
Оценка:
Здравствуйте, Abyx, Вы писали:

A>к тому же такое решение нарушает Закон Деметры


Это неправильный и вредный закон, нарушающий принцип разбиения сложного на составные части.
Re[3]: [C++] наследование vs агрегация
От: igna Россия  
Дата: 13.05.11 11:59
Оценка:
Здравствуйте, Abyx, Вы писали:

A>классы PlumesCounter и RegistryImpl это детали реализации CorvusRegistry, коду использующему CorvusRegistry о них знать не надо


Детали реализации, говоришь? Возьми свое решение с публичным наследованием и измени интерфейс какой-нибудь "детали реализации".
Re[4]: [C++] наследование vs агрегация
От: Abyx Россия  
Дата: 13.05.11 13:47
Оценка:
Здравствуйте, igna, Вы писали:

A>>классы PlumesCounter и RegistryImpl это детали реализации CorvusRegistry, коду использующему CorvusRegistry о них знать не надо


I>Детали реализации, говоришь? Возьми свое решение с публичным наследованием и измени интерфейс какой-нибудь "детали реализации".


в худшем случае будет

struct CorvusRegistry : PlumesCounter, RegistryImpl
{
    CorvusRegistry() { regImpl.setCounter(*this); }

    void update(uint corvusId, uint corvusType, uint plumeCount)
    {
        RegistryImpl::someMethodName(...);
    }
};
In Zen We Trust
Re[5]: [C++] наследование vs агрегация
От: igna Россия  
Дата: 13.05.11 14:34
Оценка:
Здравствуйте, Abyx, Вы писали:

A>struct CorvusRegistry : PlumesCounter, RegistryImpl
A>{
A>    CorvusRegistry() { regImpl.setCounter(*this); }

A>    void update(uint corvusId, uint corvusType, uint plumeCount)
A>    {
A>        RegistryImpl::someMethodName(...);
A>    }
A>};


А CorvusRegistry::someMethodName зачем?
Re[6]: [C++] наследование vs агрегация
От: Abyx Россия  
Дата: 13.05.11 15:00
Оценка:
Здравствуйте, igna, Вы писали:

I>А CorvusRegistry::someMethodName зачем?


а о нём никто не знает.
кроме того someMethodName можно сделать protected
In Zen We Trust
Re: [C++] наследование vs агрегация
От: _nn_ www.nemerleweb.com
Дата: 17.05.11 12:58
Оценка:
Здравствуйте, Abyx, Вы писали:

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

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

Если у вас этот случай повторяется более одного раза, можно воспользоваться Mixin Pattern , который реализуется с помощью CRTP:
template<typename T>
class PlumesCounterImpl
{
public:
    uint getCount(uint corvusType) { static_cast<T*>(this)->counter.getCount(corvusType); }
    void changeCount(uint corvusType, int delta); // ...
    void setCount(uint corvusType, uint value);
    void reset();
    bool wasUpdated();
};

class CorvusRegistry : PlumesCounterImpl<CorvusRegistry>
{
  ...

private:
 PlumesCounter counter;
}


Если вас устроит хак в виде наследования, то пожалуйста, можете использовать его.
Но потом не жалуйтесь на проблемы в коде
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: [C++] наследование vs агрегация
От: Abyx Россия  
Дата: 17.05.11 13:11
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Если вас устроит хак в виде наследования, то пожалуйста, можете использовать его.

__>Но потом не жалуйтесь на проблемы в коде

а какие именно проблемы могут возникнуть?
компилятор выдавал мне предупреждение "'class1' : inherits 'class2::member' via dominance", но я не понял что в этом плохого
In Zen We Trust
Re[3]: [C++] наследование vs агрегация
От: _nn_ www.nemerleweb.com
Дата: 17.05.11 13:50
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, _nn_, Вы писали:


__>>Если вас устроит хак в виде наследования, то пожалуйста, можете использовать его.

__>>Но потом не жалуйтесь на проблемы в коде

A>а какие именно проблемы могут возникнуть?

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

A>компилятор выдавал мне предупреждение "'class1' : inherits 'class2::member' via dominance", но я не понял что в этом плохого

Тут ясно написано что это означает.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: [C++] наследование vs агрегация
От: Abyx Россия  
Дата: 17.05.11 15:15
Оценка:
Здравствуйте, _nn_, Вы писали:

A>>а какие именно проблемы могут возникнуть?

__>Проблема наследования, которую вы уже привели.
__>Можно неявно преобразовать экземпляр класса в базовый класс и это может произойти там где вам это не нужно.
если вы про срезку — так это с любым наследованием, и от этого помогает noncopyable

к тому же непонятно как можно случайно обратиться к базовому классу, если он деталь реализации (он может быть в namespace detail, иметь имя xyzImpl)

A>>компилятор выдавал мне предупреждение "'class1' : inherits 'class2::member' via dominance", но я не понял что в этом плохого

__>Тут ясно написано что это означает.
я понимаю что это означает, мне непонятно что в этом плохого
In Zen We Trust
Re[5]: [C++] наследование vs агрегация
От: _nn_ www.nemerleweb.com
Дата: 17.05.11 15:23
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, _nn_, Вы писали:


A>>>а какие именно проблемы могут возникнуть?

__>>Проблема наследования, которую вы уже привели.
__>>Можно неявно преобразовать экземпляр класса в базовый класс и это может произойти там где вам это не нужно.
A>если вы про срезку — так это с любым наследованием, и от этого помогает noncopyable

A>к тому же непонятно как можно случайно обратиться к базовому классу, если он деталь реализации (он может быть в namespace detail, иметь имя xyzImpl)


В этом случае конечно никто не будет трогать базовый класс.
Но ведь у вас классы PlumesCounter и RegistryImpl общедоступны ?

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


A>>>компилятор выдавал мне предупреждение "'class1' : inherits 'class2::member' via dominance", но я не понял что в этом плохого

__>>Тут ясно написано что это означает.
A>я понимаю что это означает, мне непонятно что в этом плохого
Плохо, что при множественном наследовании с виртуальными функциями будут не всегда очевидные вызовы.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: [C++] наследование vs агрегация
От: SV.  
Дата: 17.05.11 15:24
Оценка:
Здравствуйте, Abyx, Вы писали:

A>есть какая-то задача, например слежение за воронами

A>надо
A> 1) вести учет ворон,
A> 2) считать суммарное число перьев у ворон одного типа

A>для этой задачи написан класс который делегирует работу двум другим классам, решающем соответствующие подзадачи

A>
A>class  PlumesCounter
A>{
A>public:
A>    uint getCount(uint corvusType);
A>    void changeCount(uint corvusType, int delta);
A>    void setCount(uint corvusType, uint value);
A>    void reset();
A>    bool wasUpdated();
A>};

A>class RegistryImpl
A>{
A>public:
A>    RegistryImpl(Counter&);

A>    void update(uint corvusId, uint corvusType, uint plumeCount);
A>    void remove(uint corvusId);
A>    void reset();
A>    uint tryGetType(uint corvusId);
A>    uint findAnyOfType(uint corvusType);
A>};

A>class CorvusRegistry
A>{
A>public:
A>    CorvusRegistry() : counter(), regImpl(counter) {}

A>    uint getCount(uint corvusType) { return counter.getCount(corvusType); }
A>    void changeCount(uint corvusType, int delta) { counter.changeCount(corvusType, delta); }
A>    void setCount(uint corvusType, uint value); // ... тоже делегирование
A>    void reset();
A>    bool wasUpdated();

A>    void update(uint corvusId, uint corvusType, uint plumeCount) { regImpl.update(corvusId, corvusType, plumeCount); }
A>    void remove(uint corvusId);
A>    void reset();
A>    uint tryGetType(uint corvusId);
A>    uint findAnyOfType(uint corvusType);

A>private:
A>    PlumesCounter counter;
A>    RegistryImpl regImpl; 
A>};
A>


A>я смотрю на это и вижу кучу строк кода от которых можно избавиться.

A>я хочу заменить агрегацию наследованием чтоб выкинуть "ненужные" строчки кода
A>
A>struct CorvusRegistry : PlumesCounter, RegistryImpl
A>{
A>    CorvusRegistry() { regImpl.setCounter(*this); }
A>};
A>


A>прав я или не прав?


Было херово — стало херово. Что такого особенного в воронах, чтобы их считать отдельно? Нужно воспользоваться подходящим классом коллекции, который поддерживает агрегирующие функции. Из того фреймворка, которым вы пользуетесь. Для дотнета это List<> и LINQ, для плюсов — например, STL'евские контейнеры и for_each.

Ваш личный код должен быть максимально простым и понятным:

enum RavenType
{
    Black = 0,
    White = 1,
}

class Raven
{
    RavenType RavenType { get; set; }
    int FeatherCount { get; set; }
}


Соответственно, задачи типа подсчета перьев воронов одного типа решаются так:

var ravens = ...;
var totalFeathers = ravens.Where(x => x.RavenType == RavenType.White).Sum(x => x.FeatherCount);


или вызовом for_each(). Если хочется избежать копипаста, сделайте свой extension-метод с констрейнтом для коллекций воронов, а уж плюсовый предикат так или иначе придется объявить.

P.S. Потом опять будут говорить, что ООП умерло. Декомпозицию надо делать нормально, а не дурные паттерны фигачить.
Re[2]: [C++] наследование vs агрегация
От: Abyx Россия  
Дата: 17.05.11 16:29
Оценка:
Здравствуйте, SV., Вы писали:

SV.>Было херово — стало херово. Что такого особенного в воронах, чтобы их считать отдельно? Нужно воспользоваться подходящим классом коллекции, который поддерживает агрегирующие функции. Из того фреймворка, которым вы пользуетесь. Для дотнета это List<> и LINQ, для плюсов — например, STL'евские контейнеры и for_each.


в заголовке темы тег [С++] значит никаких LINQ и extension-методов

SV.>задачи типа подсчета перьев воронов одного типа решаются так:


SV.>
SV.>var ravens = ...;
SV.>var totalFeathers = ravens.Where(x => x.RavenType == RavenType.White).Sum(x => x.FeatherCount);
SV.>


это замена алгоритма O(1) когда перья уже сосчитаны на O(N) когда их надо считать каждый раз по-новой.

В C++ нет extension-методов, и единственный способ поменять поведение контейнера — это агрегировать его в свой класс

В С++ нет IEnumerable, по этому мы не можем написать
IEnumerable ravens = ...;

мы должны указать конкретный контейнер, например vector<Raven> что сразу вытаскивает деталь реализации в интерфейс, мы уже не можем свободно поменять контейнер например на set или map, не можем поменять значение хранимое в контейнере (без динамического полиморфизма)
(есть boost::any_range, но не уверен что там будет просто поменять set на map)
In Zen We Trust
Re: [C++] наследование vs агрегация
От: maxkar  
Дата: 18.05.11 14:38
Оценка:
Здравствуйте, Abyx, Вы писали:


A>я смотрю на это и вижу кучу строк кода от которых можно избавиться.

A>я хочу заменить агрегацию наследованием чтоб выкинуть "ненужные" строчки кода

Угу. Я тоже вижу кучу лишних строчек кода. Только вот агрегацию на наследование менять не хочу. Меня больше смущает наличие setCount, делегируемый счетчику, и update/remove, делегируемые RegistryImpl. Отсюда и вопрос — счетчики должны меняться при изменении списка ворон? И почему можно внешним вмешательством перевести счетчики в невалидное состояние? Так что changeCount и setCount из этого интерфейса стоило бы отломать.

Далее, wasUpdated относится к счетчикам или ко всему реестру? При добавлении лысого ворона она правильно изменит свое значение? Т.е. обновится или нет? Ну и reset в clear здесь бы переименовать. Вообще, список воронов и статистика по ним — это разные объекты. Их то как раз можно выделять с явным интерфейсом:
struct RavensWithStatistics {
  Registry ravens;
  PlumesCounter stats;
}

Здесь Registry и PlumesCounter — абстрактные классы (фактически "интерфейсы") предоставляемые библиотекой. Логикой создания может заниматься отдельная функция (или несколько функций с разными типами параметров и т.п.). Реализация "интерфейсов" (конкретные наследники) могут вполне скрывать какие-угодно детали реализации.

Еще вопрос. А зачем писать "отдельный фасад", если все методы можно перенести в RegistryImpl и не мучиться? Он же все равно о счетчиках знает, пусть их и делегирует. Да и без счетчиков он бесполезен.

Далее, зачем привязка классов к предметной области? Вот почему классы называются по тому, как они будут использоваться в коде, а не по тому, что они делают? Вот PlumesCounter. Это же не PlumesCounter. Это вообще набор абстрактных счетчиков. Вот и стоит его называть CountersGroup (или как-то похоже) и класть в общую библиотеку. А то будут счетчики перьев для птиц, счетчики чешкек для рыб и т.п. С RegistryImpl еще непонятнее. Он точно должен быть отдельным классом и инкапсулировать какую-то логику внутри? Или вам просто нужно было к колекции добавить пару методов (tryGetType и findAnyOfType)?. Кстати, зачем вообще RegistryImpl получать количество перьев, ведь его получить никак нельзя . Так что при желании вместо этого класса берется стандартная коллекция, пишется несколько методов, работающих с коллекцией птиц (поиски ваши) и к этой конструкции пишется фасад.

Итого. Пока два решения. Первое выше — с публичной "записью", возвращаемой из метода. И публичными интерфейсами, если это где-то нужно.
Второе. Счетчики — отдельным классом. Список (существующий RegistryImpl) — либо стандартная коллекция и несколько методов, либо отдельный класс (если логика сложная внутри), но без всяких ссылок на счетчик внутри. И "фасад", который делегирует вызовы хранилищам и счетчику (при необходимости). При этом фасад еще и методы модификации лишние закрывать должен.
Re: [C++] наследование vs агрегация
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 18.05.11 15:11
Оценка:
Здравствуйте, Abyx, Вы писали:

A>есть какая-то задача, например слежение за воронами

A>надо
A> 1) вести учет ворон,
A> 2) считать суммарное число перьев у ворон одного типа

A>для этой задачи написан класс который делегирует работу двум другим классам, решающем соответствующие подзадачи


[skip]

Для начала, у тебя тут путаница из-за употребления терминов. Impl-классы как правило агрегируют по ссылке или по указателю, иначе нет смысла давать такое абстрактное название. То есть идиоматическая реализация выглядит примерно так:

// CorvusRegistry.h

class RegistryImpl;

class CorvusRegistry
{
public:
  CorvusRegistry();
protected:
  RegistryImpl *pRegistry_;
};


Где-то за два каталога от CorvusRegistry.h:
// CorvusRegistry.cpp
#include "RegistryImpl.h" // << не доступен из CorvusRegistry.h

CorvusRegistry::CorvusRegistry() : pRegistry(new RegistryImpl){}


Иными словами, Impl-класс нужен для того, чтобы скрыть детали реализации от пользователей интерфейсного класса (в данном случае — CorvusRegistry). А у тебя получается так, что RegistryImpl виден всем.

Либо RegistryImpl должен иметь какое-то более конкретное название, скажем, FileRegistry, тогда его можно без лишнего удивления агрегировать по значению любым методом: хоть агрегацией, хоть наследованием.

A>я смотрю на это и вижу кучу строк кода от которых можно избавиться.

A>я хочу заменить агрегацию наследованием чтоб выкинуть "ненужные" строчки кода
A>
A>struct CorvusRegistry : PlumesCounter, RegistryImpl
A>{
A>    CorvusRegistry() { regImpl.setCounter(*this); }
A>};
A>


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

A>прав я или не прав?


На мой взгляд, в данном случае так делать не надо, появятся лишние зависимости пользовательского кода от RegistryImpl и PlumesCounter. Но "не надо" не означает "нельзя": вполне возможно, что в твоём случае эти самые самые лишние зависимости не страшны.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[2]: [C++] наследование vs агрегация
От: Abyx Россия  
Дата: 18.05.11 16:43
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Угу. Я тоже вижу кучу лишних строчек кода. Только вот агрегацию на наследование менять не хочу. Меня больше смущает наличие setCount, делегируемый счетчику, и update/remove, делегируемые RegistryImpl. Отсюда и вопрос — счетчики должны меняться при изменении списка ворон? И почему можно внешним вмешательством перевести счетчики в невалидное состояние? Так что changeCount и setCount из этого интерфейса стоило бы отломать.


гхм.. действительно, посмотрел — у меня в проекте Counter::changeCount используется только внутри RegistryImpl, а Counter::setCount не используется вообще %)
видимо я добавил их на всякий случай, а случай не случился =\

M>Далее, wasUpdated относится к счетчикам или ко всему реестру? При добавлении лысого ворона она правильно изменит свое значение? Т.е. обновится или нет?


только к счетчикам, вообще это сомнительный метод, он нужен для оптимизации обновления GUI, чтобы "когда летит стая ворон", не уведомлять GUI о каждой, а в конце проверить были изменения или нет, при чтении оно сбрасывается

M>Вообще, список воронов и статистика по ним — это разные объекты. Их то как раз можно выделять с явным интерфейсом:

M>
M>struct RavensWithStatistics {
M>  Registry ravens;
M>  PlumesCounter stats;
M>}
M>

M>Здесь Registry и PlumesCounter — абстрактные классы (фактически "интерфейсы") предоставляемые библиотекой. Логикой создания может заниматься отдельная функция (или несколько функций с разными типами параметров и т.п.). Реализация "интерфейсов" (конкретные наследники) могут вполне скрывать какие-угодно детали реализации.
Таки нет. веткой выше предлагали вообще не делать Counter, а если надо посчитать число перьев — вызывать std::count_if
И именно так я и хотел в начале сделать. Был бы 1 класс Registry и он бы считал количество перьев когда его попросят.

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

M>Еще вопрос. А зачем писать "отдельный фасад", если все методы можно перенести в RegistryImpl и не мучиться? Он же все равно о счетчиках знает, пусть их и делегирует. Да и без счетчиков он бесполезен.

вот я как раз таки унаследовал Registry от RegistryImpl и все методы Registry перенеслись в RegistryImpl (или наоборот?),
а счетчики аггрегируются, благо там всего два метода прокинуть — getCount и wasUpdated (changeCount/setCount оказались не нужны в интерфейсе).

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

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

однако, если мне еще раз понадобится делать счетчики — я всегда могу написать реюзабельный класс и заменить им старый не реюзабельный
In Zen We Trust
Re[2]: [C++] наследование vs агрегация
От: Abyx Россия  
Дата: 18.05.11 16:50
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Для начала, у тебя тут путаница из-за употребления терминов. Impl-классы как правило агрегируют по ссылке или по указателю, иначе нет смысла давать такое абстрактное название. То есть идиоматическая реализация выглядит примерно так:


Impl это от слова implementation, по русски — реализация, а не от идиомы pimpl

ГВ>Если применять наследование именно по такому сценарию — для "упрощения" делегирования, то возможна одна неприятность: если изменится контракт любого базового класса, это изменение может отразиться на пользователях CorvusRegistry. Это может быть багой, а может быть фичей, зависит от способа использования CorvusRegistry.


в данном случае при изменениях базовых классов я собираюсь менять потомка так чтобы классы использующие потомка ничего не заметили
In Zen We Trust
Re[3]: [C++] наследование vs агрегация
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 20.05.11 01:02
Оценка:
Здравствуйте, Abyx, Вы писали:

ГВ>>Для начала, у тебя тут путаница из-за употребления терминов. Impl-классы как правило агрегируют по ссылке или по указателю, иначе нет смысла давать такое абстрактное название. То есть идиоматическая реализация выглядит примерно так:


A>Impl это от слова implementation, по русски — реализация, а не от идиомы pimpl


Тогда я не понимаю, зачем вообще городить класс реестра и к нему отдельный класс Implementation. Это всё основательно сбивает с толку тех, кто читает код.

ГВ>>Если применять наследование именно по такому сценарию — для "упрощения" делегирования, то возможна одна неприятность: если изменится контракт любого базового класса, это изменение может отразиться на пользователях CorvusRegistry. Это может быть багой, а может быть фичей, зависит от способа использования CorvusRegistry.


A>в данном случае при изменениях базовых классов я собираюсь менять потомка так чтобы классы использующие потомка ничего не заметили


Хех, если так, то лучше использовать агрегацию или защищённое (private или protected) наследование — всё равно ты собираешься изолировать пользователей от влияния базовых классов.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.