Re[4]: Саморегистрация классов в фабрике
От: remark Россия http://www.1024cores.net/
Дата: 18.03.06 17:14
Оценка:
Здравствуйте, Аноним, Вы писали:


R>>Нет, там другое.

R>>Часть функциональности, о которой я говорю там есть. Но только часть, причём не главная. Там нет саморегистрации.
А>ИМХО, как раз основое (оно же главное) там есть. Добавлена только саморегистрация, что есть довольно сомнительное приобретение.

Ну нет же, совсем нет так. В Loki есть только фабрика. Да она хорошо и удобно сделана. Но это давно известная и так сказать простая вещь. Всё что она делает создаёт по идентификатору типа объект типа. И не более.
Я же говорю, о более высокоуровневой функциональности, о метаклассах. Т.е. появляется возможность делать такие вещи как перебрать все типы, получить какие-то их свойства, получить название типа, которое можно вывести пользователю. И всё это удобно для пользователей инфраструктуры. Ничего даже рядом нет в Loki, там есть только создание объектов.
Создание объектов, конечно, важная функциональноть. Но не главная. Если бы я решил только эту задачу, то я бы не стал заводить топик.


А>В "классической" реализации фабрики классов есть возможность собрать вызовы Register в одном месте, что очень удобно при большом количестве "продуктов".


Вопрос спорный. То, о чём говоришь ты, как раз называют плохо расширяемым дизайном. Когда в одном месте много чего-то и это место надо постоянно править. А когда данные распределены и локализованы, это называют расширяемым дизайном. Добавил класс в одном месте и всё заработало. Не надо править в нескольких местах, не надо трогать старый отлаженный код, как предлагаешь ты.


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


Это зависит от идентификатора класса. Если это например название элемента в XML-файле, то не придётся лазить, что бы найти следующий неиспользованный идентификатор. Потомучто это уже проектировщик решит, что элемент называется, например, "person".
Или, если например, если идентификаторы связаны с каким-то протоколом. То тоже не придётся лазить, уже известно, что поддерживаем новый тип с кодом, например, 47.



R>>Там нет возможности нагружать эту инфроструктуру дополнительной функциоанльностью. То о чём я говорю — своего рода метаинформация или рефлекшн — и соответственно код на более высоком уровне.

А>Вот тут хотелось бы поподробнее. Смысл фабрики — сокрытие типов. Откуда возьмётся информация?

А>
А>    IHeader::Ptr h1 = HeaderFactory::create(48);
А>    h1 ... что дальше? IS_SIMPLE? как?
А>


IS_SIMPLE относится не к экземпляру, а к типу. Не путай это. Т.е это должно выглядеть как:

bool IsSimple = HeaderFactory::IsSimpleType(48);


Хотя, конечно, метод IsSimpleType() можно вынести в IHeader, а его реализацию в Header<>, тогда будет работать как ты хочешь.



R>>Хотя, возможно, мой класс фабрики можно относледовать от класса Loki::Factory, что бы заюзать часть функциональности.

А>)))))

Не понимаю, чего смешного


R>>Плюсы:

R>>1. Практически нулевое дублирование, что важно для сопровождаемого кода
А>)
R>>2. Инрастуктура функциональная, расширяемая и "умная"
А>Loki::Factory
R>>3. Сами классы реализаций интерфейсов абсолютно самодостаточные, самоописываемые, т.е. высокая локальность данных и R>функций
А>Это уж как их реализует пользователь этой фабрики.
R>>4. Чтобы добавить новый класс реализации надо просто его описать и его поддержка автоматически появиться везде где R>она должна быть. Чем не может похвастаться традиционный подход — саму реализацию добавил, добавил её поддержку в R>фабрику, добавил её поддержку в интерфейс пользователя, а при загрузке из БД забыл.
А>Про обратную сторону медали этого удобства я уже писал.

А>Резюмируя: к Loki::Factory добавлено две примочки, одна из которых может быть полезна при условии, что реализация продуктов сконцентрирована в очень небольшом числе модулей, а вторая просто бессмыслена.

А>)

Мне лично, она не кажется бессмысленной. Я применял такое решение на практике. И получал от него вполне практическую выгоду.




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Саморегистрация классов в фабрике
От: rg45 СССР  
Дата: 18.03.06 19:14
Оценка:
" Аноним " <0@users.rsdn.ru> сообщил/сообщила в новостях следующее: news:1789146@news.rsdn.ru...
> Так это, с чего всё начиналось -
> да, switch'а нет, зато есть std::map, что в плане производительности ещё хуже

ИМХО в данной, весьма общей, постановке задачи больший интерес представляет построение максимально универсального решения, а не быстрого и специализированного. Тем более, что во многих случаях будет возможность оптимизацию по скорости сделать дополнительной примочкой к общему решению. Например можно реализовать автоматическое присвоение числовых идентификаторов классов в ран тайме, если строить дополнительный статический мап для перекодировки строки в число. А доступ к идентификатору предоставлять через статичекскую переменную и виртуальный метод. Это как пример, при решении других задач могут быть еще какие то приемы оптимизации.
Posted via RSDN NNTP Server 2.0
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: Саморегистрация классов в фабрике
От: Аноним  
Дата: 18.03.06 19:49
Оценка:
Здравствуйте, rg45, Вы писали:


R>" Аноним " <0@users.rsdn.ru> сообщил/сообщила в новостях следующее: news:1789146@news.rsdn.ru...

>> Так это, с чего всё начиналось -
>> да, switch'а нет, зато есть std::map, что в плане производительности ещё хуже

R>ИМХО в данной, весьма общей, постановке задачи больший интерес представляет построение максимально универсального решения, а не быстрого и специализированного. Тем более, что во многих случаях будет возможность оптимизацию по скорости сделать дополнительной примочкой к общему решению. Например можно реализовать автоматическое присвоение числовых идентификаторов классов в ран тайме, если строить дополнительный статический мап для перекодировки строки в число. А доступ к идентификатору предоставлять через статичекскую переменную и виртуальный метод. Это как пример, при решении других задач могут быть еще какие то приемы оптимизации.


Каким образом ваше "максимально универсальное решение" позволит создавать такие классы у которохых разные конструкторы, но все есс-но потомки IHeader?

struct IHeader
{
    typedef boost::shared_ptr<IHeader> Ptr;
    virtual ~IHeader() = 0 {};
};

struct Header1
{
    Header1(int);
};

struct Header2
{
    Header2(double);
};

struct Header3
{
    Header3(Ptr);
};


фабрика в зависимости от параметра {1,2,3} должна создать классы {Header1,Header2,Header3} соответственно. Как в эту фабрику передать аргументы конструкта, причем, разных конструкторов??
Re[4]: Саморегистрация классов в фабрике
От: rg45 СССР  
Дата: 18.03.06 20:10
Оценка:
" Аноним " <0@users.rsdn.ru> сообщил/сообщила в новостях следующее: news:1790791@news.rsdn.ru...
> Каким образом ваше "максимально универсальное решение" позволит создавать такие классы у которохых разные конструкторы, но все есс-но потомки IHeader?
> фабрика в зависимости от параметра {1,2,3} должна создать классы {Header1,Header2,Header3} соответственно. Как в эту фабрику передать аргументы конструкта, причем, разных конструкторов??

Да в принципе реализовать не сложно, если базовая абстракная фабрика имеет перегруженные операции create_object c соответствующими параметрами.
Только не совсем ясна практическая ценность этой задачи, и какой смысл это решение обобщать?
Posted via RSDN NNTP Server 2.0
--
Справедливость выше закона. А человечность выше справедливости.
Re[5]: Саморегистрация классов в фабрике
От: Аноним  
Дата: 18.03.06 20:39
Оценка:
Здравствуйте, rg45, Вы писали:


R>" Аноним " <0@users.rsdn.ru> сообщил/сообщила в новостях следующее: news:1790791@news.rsdn.ru...

>> Каким образом ваше "максимально универсальное решение" позволит создавать такие классы у которохых разные конструкторы, но все есс-но потомки IHeader?
>> фабрика в зависимости от параметра {1,2,3} должна создать классы {Header1,Header2,Header3} соответственно. Как в эту фабрику передать аргументы конструкта, причем, разных конструкторов??

R>Да в принципе реализовать не сложно, если базовая абстракная фабрика имеет перегруженные операции create_object c соответствующими параметрами.

R>Только не совсем ясна практическая ценность этой задачи, и какой смысл это решение обобщать?

Практическая ценность очевидна, конструктор это единственная функция наследников, которая может иметь произвольное описание, тогда как интерфейс фиксирован, в том числе и список аргументов виртуальных методов. Т. е. через конструктор моежно настраивать поведение неследников от общего интерфейса (см. обсуждение ниже по ветке).
Re: Саморегистрация классов в фабрике
От: MaximE Великобритания  
Дата: 18.03.06 21:10
Оценка: +2
remark wrote:
>
> Решение для типовой задачи, когда есть интерфейс, реализации интерфейса,
> и реализации создаются фабрикой по некоторому значению (типу
> реализации). В решении обеспечивается саморегистрация классов реализаций
> интерфейса в фабрике, т.о. отпадает необходимость в switch'е в фабрике,
> и решение становиться максимально открытым для расширения.
> Может кому будет полезно. Или кто выскажет конструктивные замечания.

Конструктивных замечаний одно: если фабрика не найдена, ты кидаешь
std::runtime_error. Конструктор объекта может выкинуть исключение того
же типа — конфуз. Лучше определить новый тип исключения для ненайденной
фабрики.

Из неконструктивных: задача тривиальна, код должен быть также прост и
ясен. Здесь же код концептуально тяжелый, надуманный. Фтопку...
Posted via RSDN NNTP Server 2.0
Re[4]: Саморегистрация классов в фабрике
От: remark Россия http://www.1024cores.net/
Дата: 18.03.06 21:15
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Каким образом ваше "максимально универсальное решение" позволит создавать такие классы у которохых разные конструкторы, но все есс-но потомки IHeader?



Это абсурд! Если у тебя есть какие-то специфические параметры конструктора для какого-то конкретного класса MySpecificHeader, то зачем вообще нужна фабрика??? Возьми да создай объект MySpecificHeader!


А>
А>struct IHeader
А>{
А>    typedef boost::shared_ptr<IHeader> Ptr;
А>    virtual ~IHeader() = 0 {};
А>};

А>struct Header1
А>{
А>    Header1(int);
А>};

А>struct Header2
А>{
А>    Header2(double);
А>};

А>struct Header3
А>{
А>    Header3(Ptr);
А>};
А>


А>фабрика в зависимости от параметра {1,2,3} должна создать классы {Header1,Header2,Header3} соответственно. Как в эту фабрику передать аргументы конструкта, причем, разных конструкторов??


Тут ты фактически ещё до вызова метода фабрики create() знаешь объект какого типа ты хочешь создать.
Ты не понимаешь смысл фабрики. Например: парсим XML: есть название элемента (которое определяет объект какого класса надо создать) и есть текстовое содержание этого элемента. Тогда мы это текстовое содержание передаём в конструктор всех объектов и соответственно в метод create() фабрики:

IElementPtr Factory::create(const std::string& ElementName, const std::string& ElementContent);


Конструктор каждой реализации принимает строку:

Element1::Element1(const std::string& ElementContent);


Каждая реализация интерфейса IElement в конструкторе вольна сделать со строкой ElementContent что угодно — оставить как текст, распарсить в int, распарсить в double или ещё что-то. Но всё это происходит уже вне фабрики.

В твоём решении ошибка в том, что ты начал выполнять какие-то специфические действия (выделять int, double, Ptr) слишком рано — до фабрики, до вызова create(). Тебе надо поставить эту специфику после фабрики — внести её в конструкторы конкретных реализаций. А до фабрики никак ничего не разделять на разные типы и т.д.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Саморегистрация классов в фабрике
От: remark Россия http://www.1024cores.net/
Дата: 18.03.06 23:09
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>remark wrote:

>>
>> Решение для типовой задачи, когда есть интерфейс, реализации интерфейса,
>> и реализации создаются фабрикой по некоторому значению (типу
>> реализации). В решении обеспечивается саморегистрация классов реализаций
>> интерфейса в фабрике, т.о. отпадает необходимость в switch'е в фабрике,
>> и решение становиться максимально открытым для расширения.
>> Может кому будет полезно. Или кто выскажет конструктивные замечания.

ME>Конструктивных замечаний одно: если фабрика не найдена, ты кидаешь

ME>std::runtime_error. Конструктор объекта может выкинуть исключение того
ME>же типа — конфуз. Лучше определить новый тип исключения для ненайденной
ME>фабрики.

Наверное, речь идёт не о ненайденной фабрике, а о ненайденном типе продукта.
Согласен. Я старался привести только идею. Я не старался довести до библиотечной реализации.
Если делать библиотечную реализацию, то я думаю надо не просто другой тип исключения бросать, надо делать поведение настраиваемое: кто-то хочет одно исключение, что-то другое, кто-то int3, кто-то вывод в журнал и т.д.


ME>Из неконструктивных: задача тривиальна, код должен быть также прост и

ME>ясен. Здесь же код концептуально тяжелый, надуманный. Фтопку...

Задача не так тривиальна как кажется. Я решаю задачу не просто создания объектов. Фактически этим я приделываю к с++ метаинформацию (рефлекшн). И позволяю решать такие задачи как: перебрать все типы; найти типы, соотв. определённому критерию; проверить, есть ли нужный тип.

з.ы. как ты думаешь навскидку какого размера в Loki файл Factory.h? 1000 строк кода.





1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: Саморегистрация классов в фабрике
От: Аноним  
Дата: 19.03.06 09:08
Оценка:
Здравствуйте, remark, Вы писали:

R>Это абсурд! Если у тебя есть какие-то специфические параметры конструктора для какого-то конкретного класса MySpecificHeader, то зачем вообще нужна фабрика??? Возьми да создай объект MySpecificHeader!


Т.е. таки старый добрый switch по индексу Вот и я о том же зачем вообще нужна фабрика?

А>>фабрика в зависимости от параметра {1,2,3} должна создать классы {Header1,Header2,Header3} соответственно. Как в эту фабрику передать аргументы конструкта, причем, разных конструкторов??


R>Тут ты фактически ещё до вызова метода фабрики create() знаешь объект какого типа ты хочешь создать.

R>Ты не понимаешь смысл фабрики. Например: парсим XML: есть название элемента (которое определяет объект какого класса надо создать) и есть текстовое содержание этого элемента. Тогда мы это текстовое содержание передаём в конструктор всех объектов и соответственно в метод create() фабрики:

Я знаю только индекс, но по этому индексу я конечно могу определить с каким классом он отождествлен и switch'ем, перебирая индексы вызову соответствующий конструктор.

R>В твоём решении ошибка в том, что ты начал выполнять какие-то специфические действия (выделять int, double, Ptr) слишком рано — до фабрики, до вызова create(). Тебе надо поставить эту специфику после фабрики — внести её в конструкторы конкретных реализаций. А до фабрики никак ничего не разделять на разные типы и т.д.


Не очень понятно. Я имею уже конкретную иерархию, например, от IHeader. Затем пользователь в диалоге выбирает какой конкретно класс IHeader нужно создать, передачей в приложение некой переменной (обычно константа из enum'а), а приложение по этой константе создает нужный класс, какой параметр передать в конструктор каждого класса приложение знает само, без информации от пользователя.

В это случае фабрику использовать не получится, насколько я понимаю, только switch?
Re[6]: Саморегистрация классов в фабрике
От: remark Россия http://www.1024cores.net/
Дата: 19.03.06 10:45
Оценка:
Здравствуйте, Аноним, Вы писали:

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


R>>Это абсурд! Если у тебя есть какие-то специфические параметры конструктора для какого-то конкретного класса MySpecificHeader, то зачем вообще нужна фабрика??? Возьми да создай объект MySpecificHeader!


А>Т.е. таки старый добрый switch по индексу Вот и я о том же зачем вообще нужна фабрика?


Я лично объект известного типа создаю вот так:

MySpecificHeader h(i);


switch я тут не применяю.



А>>>фабрика в зависимости от параметра {1,2,3} должна создать классы {Header1,Header2,Header3} соответственно. Как в эту фабрику передать аргументы конструкта, причем, разных конструкторов??


R>>Тут ты фактически ещё до вызова метода фабрики create() знаешь объект какого типа ты хочешь создать.

R>>Ты не понимаешь смысл фабрики. Например: парсим XML: есть название элемента (которое определяет объект какого класса надо создать) и есть текстовое содержание этого элемента. Тогда мы это текстовое содержание передаём в конструктор всех объектов и соответственно в метод create() фабрики:

А>Я знаю только индекс, но по этому индексу я конечно могу определить с каким классом он отождествлен и switch'ем, перебирая индексы вызову соответствующий конструктор.


R>>В твоём решении ошибка в том, что ты начал выполнять какие-то специфические действия (выделять int, double, Ptr) слишком рано — до фабрики, до вызова create(). Тебе надо поставить эту специфику после фабрики — внести её в конструкторы конкретных реализаций. А до фабрики никак ничего не разделять на разные типы и т.д.


А>Не очень понятно. Я имею уже конкретную иерархию, например, от IHeader. Затем пользователь в диалоге выбирает какой конкретно класс IHeader нужно создать, передачей в приложение некой переменной (обычно константа из enum'а), а приложение по этой константе создает нужный класс, какой параметр передать в конструктор каждого класса приложение знает само, без информации от пользователя.

А>В это случае фабрику использовать не получится, насколько я понимаю, только switch?


Помедетируй над своей фразой "какой параметр передать в конструктор каждого класса приложение знает само, без информации от пользователя". Каким образом приложение это знает? Как это будет реализовано?

Ценность фабрики становиться нулевой, если у тебя перед вызовом create() стоит switch, который определяет типы параметров, которые надо передать каждому конкретному классу.

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

Второй вариант решения: использовать создающую функцию:

class Header1 : public Header<Header1>
{
...
IHeader::Ptr create();
...
};


Т.е. в каждом классе продукта должа быть функция, которая не принимает параметров и создаёт объект. HeaderWrapper<> будет использовать эти функции для создания продуктов в фабрике. Но в каждой конкретной функции create() ты волен производить любые вычисления и передавать в конструктор любой произвольный набор параметров.



Суть фабрики в том, что бы весь твой код приложения ничего не знал о конкретных классах продуктов. То есть вообще ничего не знал. Что бы ему было фиолетово, когда новые классы продуктов появляются, удаляются изменяются и т.д. Именно для этого нужен интерфейс класса продукта и фабрика. И тут своего рода должен быть интерфейс конструктора, хотя в интерфейсе IHeader его выразить и не удаётся, но его нужно поддерживать или с помощью того, что все конструкторы принимают одинаковый набор параметров или с помощью производящей функции или с помощью клонов или ещё как-то. Тогда и только тогда появляется смысл в использовании фабрики. Если ты не можешь обеспечить одинаковое конструирование, то тебе нет смысла даже смотреть в сторону фабрики.

Когда я строю решение на основе такой фабрики с саморегистрацией заголовочный файл с описанием конкретного продукта (Header1.h, Header2.h и т.д.) я включаю только в соответствующий cpp'шник (Header1.cpp, Header2.cpp и т.д.). Всё! Больше никуда! В один файл. think about it.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Саморегистрация классов в фабрике
От: programmater  
Дата: 19.03.06 12:58
Оценка:
Здравствуйте, remark, Вы писали:

R>Решение для типовой задачи, когда есть интерфейс, реализации интерфейса, и реализации создаются фабрикой по некоторому значению (типу реализации). В решении обеспечивается саморегистрация классов реализаций интерфейса в фабрике, т.о. отпадает необходимость в switch'е в фабрике, и решение становиться максимально открытым для расширения.

R>Может кому будет полезно. Или кто выскажет конструктивные замечания.
[кусь]
Долго пытался разобраться. Вроде бы разобрался . Замечания выскажу. Насчет конструктивности не уверен . В целом за идею спасибо. Полезно будет.
R>В принципе тут можно уменьшить кол-во классов путём совмещения: например код из HeaderFactory можно поместить в IHeader. Тут так сказать всё разложено по полочкам.
Согласен. ИМХО фабрику лучше иметь отдельно.

R>Заполнение фабрики информацией о реализациях происходит во время инициализации глобальных объектов. Т.е. уже к main() она "константная".

Да мне бы и ран-тайм саморегистрация подошла бы. Иногда так бывает надо . Твой плюс в том, что у тебя "domain" саморегистрация (т.е. саморегистрация до вызова main ) автоматическая.
R>Сразу предвижу замечания по поводу оверхеда. Возможно он есть тут.
Ага. Первое, что хотелось заорать — а можно без буст/локи/шмоки/traits-ов в темплейтах??? Ну почему использование этих новомодных библиотек/концепций/фич считается круто? Или "передовики объектно-ориентированной мысли" просто жить без этого не могут? Если можно, вырази мысль "более простым" языком. Лично я буст/локи не знаю совсем. Темплейты немного знаю, но не настолько, чтобы рожать строки подобно
template<typename HeaderType> typename Header<HeaderType>::Initializer Header<HeaderType>::initializer;

которую понимал минут 10 . И trairs пока "не умею готовить" .

R>Конечно для тривиальных случаев делать так не стоит. Но для сложных, я считаю такое решение оправдано. Зато это создаёт некую инфраструктуру, с которой "пользовательские классы" становяться проще. Зато тут всё ортогонально и все классы и методы простые, короткие и понятные.

Согласен. У самого никогда руки не доходили до конца создать такую структуру. Надеюсь основную идею я понял и смогу сам упростить (имеется в виду в первую очередь выкинуть boost::тра-ля-ля и заменить чем-то более съедобным) для своих целей. Хотя если это сделает автор, буду ему благодарен.
R>А с "более простыми решения" рука об руку идут switch'и, дублирование и другие прелести.
Ну про switch уже сказали: map::find выполняется дольше switch. Для тех, кто не в курсе: если вы думаете, что switch — это последовательный if — то вы глубоко не правы. Современные оптимизирующие компиляторы стали довольно умными и научились превращать switch в поиск в отсортированном массиве, так что количество "итераций" порядка log2(N). Сию страшную тайну мне открыл MaximE. А учитывая, что сама "итерация" в случае с map длинее, то map::find в плане быстродействия проигрывает switch-у. Но идея от этого хуже не становится. В сложных случаях накладные расходы от map.find будут пренебрежимо малыми, а пользы от структурированности будет гораздо больше.

[кусь]
R>... что-то уже до целой статьи дотягивает

R>
Re: Саморегистрация классов в фабрике
От: Константин Ленин  
Дата: 19.03.06 14:42
Оценка:
Здравствуйте, remark, Вы писали:

R>Решение для типовой задачи, когда есть интерфейс, реализации интерфейса, и реализации создаются фабрикой по некоторому значению (типу реализации). В решении обеспечивается саморегистрация классов реализаций интерфейса в фабрике, т.о. отпадает необходимость в switch'е в фабрике, и решение становиться максимально открытым для расширения.

R>Может кому будет полезно. Или кто выскажет конструктивные замечания.

Не понравилось, что в реализации добавляются лишние данные(TYPE etc.). Лучше бы это вынести в отдельный класс, что-то типа typetraits
Re[2]: Саморегистрация классов в фабрике
От: Константин Ленин  
Дата: 19.03.06 15:00
Оценка:
Здравствуйте, Константин Ленин, Вы писали:

КЛ>Здравствуйте, remark, Вы писали:


R>>Решение для типовой задачи, когда есть интерфейс, реализации интерфейса, и реализации создаются фабрикой по некоторому значению (типу реализации). В решении обеспечивается саморегистрация классов реализаций интерфейса в фабрике, т.о. отпадает необходимость в switch'е в фабрике, и решение становиться максимально открытым для расширения.

R>>Может кому будет полезно. Или кто выскажет конструктивные замечания.

КЛ>Не понравилось, что в реализации добавляются лишние данные(TYPE etc.). Лучше бы это вынести в отдельный класс, что-то типа typetraits


Что-то типа этого



namespace HeaderDetails
{

template <typename T>
class HeaderTypeTraits{};

}

template<typename Derived>
struct Header : IHeader
{
private:
    struct Initializer
    {
        Initializer()
        {
            // Саморегистрация
            HeaderFactory::add( HeaderTypeTraits<Derived>::TYPECODE , IHeaderWrapper::Ptr(new HeaderWrapper<Derived>));
        }
    };

    static Initializer initializer;

protected:
    ~Header()
    {
        // Надо обязательно заюзать эту переменную
        (void)initializer;
    }
};

class RealHeader : public ...


namespace HeaderDetails
{

template <>
class HeaderTypeTraits<RealHeader>
{
     static const int TYPECODE = 0;
};

}


А если к этому, как заметил _nn_, прикрутить еще и автоинкремент ID...
Только вот придется для каждого наследника писать специализацию HeaderTypeTraits, но зато не надо будет их нагружать ненужной информацией
Re[2]: Саморегистрация классов в фабрике
От: remark Россия http://www.1024cores.net/
Дата: 19.03.06 15:04
Оценка:
Здравствуйте, programmater, Вы писали:


R>>Заполнение фабрики информацией о реализациях происходит во время инициализации глобальных объектов. Т.е. уже к main() она "константная".

P>Да мне бы и ран-тайм саморегистрация подошла бы. Иногда так бывает надо . Твой плюс в том, что у тебя "domain" саморегистрация (т.е. саморегистрация до вызова main ) автоматическая.
R>>Сразу предвижу замечания по поводу оверхеда. Возможно он есть тут.
P>Ага. Первое, что хотелось заорать — а можно без буст/локи/шмоки/traits-ов в темплейтах??? Ну почему использование этих новомодных библиотек/концепций/фич считается круто? Или "передовики объектно-ориентированной мысли" просто жить без этого не могут? Если можно, вырази мысль "более простым" языком. Лично я буст/локи не знаю совсем. Темплейты немного знаю, но не настолько, чтобы рожать строки подобно

Ну там из boost'а то всего лишь shared_ptr. Если не нравится, то можешь boost ::shared_ptr<Something> заменить на Something*. Только тогда надо будет объект потом вручную удалять.

Дело не в том, что модно или без них нельзя. Дело в том, что там реализовано очень много распростанённых вещей. Если без них, то просто придётся реализовывать это всё руками, причём оно будет выглядеть практически идентично с реализацией в boost. Спрашивается, а смысл?

Ну, например, зачем мы используем std::vector? А можно без него?
Можно, конечно, но только самому в конце концов придётся его реализовать... Лучше всё равно врядли получится...


P>
P>template<typename HeaderType> typename Header<HeaderType>::Initializer Header<HeaderType>::initializer;
P>

P>которую понимал минут 10 . И trairs пока "не умею готовить" .

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




R>>Конечно для тривиальных случаев делать так не стоит. Но для сложных, я считаю такое решение оправдано. Зато это создаёт некую инфраструктуру, с которой "пользовательские классы" становяться проще. Зато тут всё ортогонально и все классы и методы простые, короткие и понятные.

P>Согласен. У самого никогда руки не доходили до конца создать такую структуру. Надеюсь основную идею я понял и смогу сам упростить (имеется в виду в первую очередь выкинуть boost::тра-ля-ля и заменить чем-то более съедобным) для своих целей. Хотя если это сделает автор, буду ему благодарен.
R>>А с "более простыми решения" рука об руку идут switch'и, дублирование и другие прелести.

P>Ну про switch уже сказали: map::find выполняется дольше switch. Для тех, кто не в курсе: если вы думаете, что switch — это последовательный if — то вы глубоко не правы. Современные оптимизирующие компиляторы стали довольно умными и научились превращать switch в поиск в отсортированном массиве, так что количество "итераций" порядка log2(N). Сию страшную тайну мне открыл MaximE. А учитывая, что сама "итерация" в случае с map длинее, то map::find в плане быстродействия проигрывает switch-у. Но идея от этого хуже не становится. В сложных случаях накладные расходы от map.find будут пренебрежимо малыми, а пользы от структурированности будет гораздо больше.



Я уже писал выше на эту тему: map тут просто для большей понятности и краткости. Фабрику можно элементарно переделать на использование отсортированного vector'а, и использовать бинарный поиск. Тем более, что он заполняется до main().
Ещё к теме использования готовых библиотек: Такой отсортированный vector с интерфейсом map уже, кстати, есть в Loki, называется AssocVector
Т.е. можно просто заменить в описании std::map на Loki::AssocVector и получишь вычислительную сложность O(log2(N)).


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Саморегистрация классов в фабрике
От: remark Россия http://www.1024cores.net/
Дата: 19.03.06 15:12
Оценка:
Здравствуйте, Константин Ленин, Вы писали:

КЛ>Здравствуйте, remark, Вы писали:


R>>Решение для типовой задачи, когда есть интерфейс, реализации интерфейса, и реализации создаются фабрикой по некоторому значению (типу реализации). В решении обеспечивается саморегистрация классов реализаций интерфейса в фабрике, т.о. отпадает необходимость в switch'е в фабрике, и решение становиться максимально открытым для расширения.

R>>Может кому будет полезно. Или кто выскажет конструктивные замечания.

КЛ>Не понравилось, что в реализации добавляются лишние данные(TYPE etc.). Лучше бы это вынести в отдельный класс, что-то типа typetraits



Согласен. Так можно сделать, у меня была такая мысль. Так:

class Header1 : public Header<Header1>
{
...
struct Meta
{
static const int TYPE = 1;
};
...
};



или так:

class Header1 : public Header<Header1>
{
...
};

templatе<>
struct Traits<Header1>
{
static const int TYPE = 1;
};
...



То, что это будет безоговорочно лучше, я бы не сказал. Писанины больше. Но зато более структурно.
Ну не знаю, кому как больше нравится.



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: Саморегистрация классов в фабрике
От: Константин Ленин  
Дата: 19.03.06 15:18
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, Аноним, Вы писали:



R>>>Нет, там другое.

R>>>Часть функциональности, о которой я говорю там есть. Но только часть, причём не главная. Там нет саморегистрации.
А>>ИМХО, как раз основое (оно же главное) там есть. Добавлена только саморегистрация, что есть довольно сомнительное приобретение.

R>Ну нет же, совсем нет так. В Loki есть только фабрика. Да она хорошо и удобно сделана. Но это давно известная и так сказать простая вещь. Всё что она делает создаёт по идентификатору типа объект типа. И не более.

R>Я же говорю, о более высокоуровневой функциональности, о метаклассах. Т.е. появляется возможность делать такие вещи как перебрать все типы, получить какие-то их свойства, получить название типа, которое можно вывести пользователю. И всё это удобно для пользователей инфраструктуры. Ничего даже рядом нет в Loki, там есть только создание объектов.
R>Создание объектов, конечно, важная функциональноть. Но не главная. Если бы я решил только эту задачу, то я бы не стал заводить топик.


А>>В "классической" реализации фабрики классов есть возможность собрать вызовы Register в одном месте, что очень удобно при большом количестве "продуктов".


R>Вопрос спорный. То, о чём говоришь ты, как раз называют плохо расширяемым дизайном. Когда в одном месте много чего-то и это место надо постоянно править. А когда данные распределены и локализованы, это называют расширяемым дизайном. Добавил класс в одном месте и всё заработало. Не надо править в нескольких местах, не надо трогать старый отлаженный код, как предлагаешь ты.


Без автоинкремента фича саморегистрации бесполезна и даже опасна. Когда коды расбросаны по всему проекту и ты должен, как тут уже говорили, искать свободный ID...Тем более это хорошо, что ты вставляешь в мап insert'ом, если бы кто-нить вставлял operator[]'ом, можно было бы таких багов насажать с одинаковыми ID...
Re[6]: Саморегистрация классов в фабрике
От: remark Россия http://www.1024cores.net/
Дата: 19.03.06 15:32
Оценка:
Здравствуйте, Константин Ленин, Вы писали:


КЛ>Без автоинкремента фича саморегистрации бесполезна и даже опасна. Когда коды расбросаны по всему проекту и ты должен, как тут уже говорили, искать свободный ID...Тем более это хорошо, что ты вставляешь в мап insert'ом, если бы кто-нить вставлял operator[]'ом, можно было бы таких багов насажать с одинаковыми ID...



Абсолютно не согласен со всеми кто писал про автоинкремент идентификаторов. Либо вы чего-то не понимаете, либо я чего-то не понимаю.
Во-первых, для меня вообще туманно реальное использование этой фичи (приведите примеры).
С автоинкрементом: идентификаторы не постоянны, не известны, их нельзя никуда отправлять/принимать/хранить в постоянной памяти. Я вижу единственныую возможность их использовать: это пересылать объект из одной части программы в другую в сериализованном виде. Зачем это нужно? Можно передать сам объект.

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

В-третьих, я уже тут писал, что во всех случаях, когда я использовал фабрики, ручное присвоение идентификаторов не просто можно, но и нужно. Ну просто без него нельзя.
Например: я парсю XML и пишу класс именно для элемента "person". Ну какое тут автоприсвоение идентификаторов?
Уже давно в БД используется формат данных, при котором если в поле XXX, лежит значение YYY, то это соответствует определённому классу. Ну какое тут автоприсвоение идентификаторов?
Если я поддерживаю какой-то протокол и в нём прописано, что пакету с таким-то типом соответствует код 47. Ну какое тут автоприсвоение идентификаторов?


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



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Саморегистрация классов в фабрике
От: remark Россия http://www.1024cores.net/
Дата: 19.03.06 15:38
Оценка:
Здравствуйте, Константин Ленин, Вы писали:

КЛ>Здравствуйте, Константин Ленин, Вы писали:


КЛ>>Здравствуйте, remark, Вы писали:


R>>>Решение для типовой задачи, когда есть интерфейс, реализации интерфейса, и реализации создаются фабрикой по некоторому значению (типу реализации). В решении обеспечивается саморегистрация классов реализаций интерфейса в фабрике, т.о. отпадает необходимость в switch'е в фабрике, и решение становиться максимально открытым для расширения.

R>>>Может кому будет полезно. Или кто выскажет конструктивные замечания.

КЛ>>Не понравилось, что в реализации добавляются лишние данные(TYPE etc.). Лучше бы это вынести в отдельный класс, что-то типа typetraits


КЛ>Что-то типа этого


КЛ>
...
КЛ>




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


КЛ>А если к этому, как заметил _nn_, прикрутить еще и автоинкремент ID...


По поводу этого я ответил здесь
Автор: remark
Дата: 19.03.06
. ОБЪЯСНИТЕ МНЕ ЧТО ВЫ ВООБЩЕ ИМЕЕТЕ В ВИДУ!



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Саморегистрация классов в фабрике
От: _nn_  
Дата: 19.03.06 16:29
Оценка:
Здравствуйте, remark, Вы писали:

<skip>

А что если объединить:
template<typename T>
struct HeaderTraits
{
 static const int TYPE = T::TYPE;
};

// ...
            // Саморегистрация
            HeaderFactory::add(HeaderTraits<Derived>::TYPE, IHeaderWrapper::Ptr(new HeaderWrapper<Derived>));


Объявляем в классе TYPE и все работает, хочется через HeaderTraits и снова нет никаких проблем.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[7]: Саморегистрация классов в фабрике
От: rg45 СССР  
Дата: 19.03.06 16:47
Оценка: 1 (1)
"remark" <38267@users.rsdn.ru> сообщил/сообщила в новостях следующее: news:1791411@news.rsdn.ru...
> Здравствуйте, Константин Ленин, Вы писали:
>
>
>
> Объясни мне ход мыслей, который приводит вас к мысли об автоприсвоении идентификаторов. Может я чего-то не понимаю.
>

В начальном ведь примере эти идентификаторы подразумевались как некоторые идентификаторы протокола, и никто не говорил, что они должны идти попорядку.
Тебе в твоем примере нужно было использовать не 1,2,3 а совершенно призвольные идентификаторы, обозвав их типа: old_protocol, current protocol, advanced_protocol.
Тогда бы было меньше соблазнов прикручивать сюда автоинкремент.
А вообще сложность этого обсуждения, ИМХО, состоит в том, что каждый его участник рассматривает задачу в какой то специфической трактовке, в результате получается спор типа: "А что слаще — синее или толстое?"
Posted via RSDN NNTP Server 2.0
--
Справедливость выше закона. А человечность выше справедливости.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.