__>Объявляем в классе TYPE и все работает, хочется через HeaderTraits и снова нет никаких проблем.
Даже не знаю, что сказать...
Если смотреть с т.з. решения задачки на с++, то прикольно.
А если серьёзно, то ИМХО чем больше выбора, тем хуже. Это на первый взгляд хорошо, что можно и так и так. Но на второй взгляд, в этом же во всём разбираться и это же всё поддерживать.
Такие решения применяются, например, в стандартной библиотеке. Например, iterator_traits. Но они там не от хорошей жизни. Не для того, что бы прикольно сделать. Они там от того, что для итератора-указателя (итератор c-массива) не получиться сделать у него члены с описанием свойств. Поэтому это вынести отдельно в traits. Или например, для встроенных типов по другому никак traits не сделаешь.
А если таких проблем нет, и все свойства можно описать прямо "не отходя от кассы", то зачем извращаться.
R>"remark" <38267@users.rsdn.ru> сообщил/сообщила в новостях следующее: news:1791411@news.rsdn.ru... >> Здравствуйте, Константин Ленин, Вы писали: >> >> >> >> Объясни мне ход мыслей, который приводит вас к мысли об автоприсвоении идентификаторов. Может я чего-то не понимаю. >>
R>В начальном ведь примере эти идентификаторы подразумевались как некоторые идентификаторы протокола, и никто не говорил, что они должны идти попорядку. R>Тебе в твоем примере нужно было использовать не 1,2,3 а совершенно призвольные идентификаторы, обозвав их типа: old_protocol, current protocol, advanced_protocol. R>Тогда бы было меньше соблазнов прикручивать сюда автоинкремент. R>А вообще сложность этого обсуждения, ИМХО, состоит в том, что каждый его участник рассматривает задачу в какой то специфической трактовке, в результате получается спор типа: "А что слаще — синее или толстое?"
Проблема, по-моему, в том, что никто из говоривших про автоикремент не подумал хорошо, перед тем как говорить. По крайней мере ещё никто не привёл вразумительного примера применения.
__>>Объявляем в классе TYPE и все работает, хочется через HeaderTraits и снова нет никаких проблем.
R>Даже не знаю, что сказать... R>Если смотреть с т.з. решения задачки на с++, то прикольно. R>А если серьёзно, то ИМХО чем больше выбора, тем хуже. Это на первый взгляд хорошо, что можно и так и так. Но на второй взгляд, в этом же во всём разбираться и это же всё поддерживать.
+1
R>Такие решения применяются, например, в стандартной библиотеке. Например, iterator_traits. Но они там не от хорошей жизни. Не для того, что бы прикольно сделать. Они там от того, что для итератора-указателя (итератор c-массива) не получиться сделать у него члены с описанием свойств. Поэтому это вынести отдельно в traits. Или например, для встроенных типов по другому никак traits не сделаешь.
Это из-за корявости языка. (Но это другая тема). R>А если таких проблем нет, и все свойства можно описать прямо "не отходя от кассы", то зачем извращаться.
Нравится некоторым
R>
Здравствуйте, remark, Вы писали:
R>Решение для типовой задачи, когда есть интерфейс, реализации интерфейса, и реализации создаются фабрикой по некоторому значению (типу реализации). В решении обеспечивается саморегистрация классов реализаций интерфейса в фабрике, т.о. отпадает необходимость в switch'е в фабрике, и решение становиться максимально открытым для расширения. R>Может кому будет полезно. Или кто выскажет конструктивные замечания.
R>protected: R> ~Header() R> { R> // Надо обязательно заюзать эту переменную R> (void)initializer; R> }
У меня (GC 3) работает только так:
protected:
~Header()
{
// Надо обязательно заюзать эту переменную
(void)initializer;
int i = 3;
i++;
}
. ОБЪЯСНИТЕ МНЕ ЧТО ВЫ ВООБЩЕ ИМЕЕТЕ В ВИДУ! Он нужен для автоматической раздачи ID, что гораздо безопаснее по сравнению с ручной. Однако если постоянность пары ID-тип должна быть всегда, то автоинкремент может быть не применим. И все, больше я ничего не имел ввиду.
. ОБЪЯСНИТЕ МНЕ ЧТО ВЫ ВООБЩЕ ИМЕЕТЕ В ВИДУ! Он нужен для автоматической раздачи ID, что гораздо безопаснее по сравнению с ручной. Однако если постоянность пары ID-тип должна быть всегда, то автоинкремент может быть не применим. И все, больше я ничего не имел ввиду.
Ну хорошо, она безопаснее, но имеет ли она хоть какую-то практическую ценность отличную от нуля? Вот какой меня сейчас мучает вопрос.
На сколько я понимаю сейчас, её практическая ценность равна нулю, и следовательно разговоры о её безопасности не имеют смысла.
. ОБЪЯСНИТЕ МНЕ ЧТО ВЫ ВООБЩЕ ИМЕЕТЕ В ВИДУ! Он нужен для автоматической раздачи ID, что гораздо безопаснее по сравнению с ручной. Однако если постоянность пары ID-тип должна быть всегда, то автоинкремент может быть не применим. И все, больше я ничего не имел ввиду.
R>Ну хорошо, она безопаснее, но имеет ли она хоть какую-то практическую ценность отличную от нуля? Вот какой меня сейчас мучает вопрос. R>На сколько я понимаю сейчас, её практическая ценность равна нулю, и следовательно разговоры о её безопасности не имеют смысла.
R>
Это почему? Далеко не каждой системе нужно постоянство пары ID-TYPE
Здравствуйте, Константин Ленин, Вы писали:
КЛ>Здравствуйте, remark, Вы писали:
R>>Здравствуйте, Константин Ленин, Вы писали:
R>>>>По поводу этого я ответил здесь
. ОБЪЯСНИТЕ МНЕ ЧТО ВЫ ВООБЩЕ ИМЕЕТЕ В ВИДУ! Он нужен для автоматической раздачи ID, что гораздо безопаснее по сравнению с ручной. Однако если постоянность пары ID-тип должна быть всегда, то автоинкремент может быть не применим. И все, больше я ничего не имел ввиду.
R>>Ну хорошо, она безопаснее, но имеет ли она хоть какую-то практическую ценность отличную от нуля? Вот какой меня сейчас мучает вопрос. R>>На сколько я понимаю сейчас, её практическая ценность равна нулю, и следовательно разговоры о её безопасности не имеют смысла.
R>>
КЛ>Это почему? Далеко не каждой системе нужно постоянство пары ID-TYPE
Мне на ум, исходя из моего опыта использования фабрик и вообще если подумать, приходят только варианты, где (1) это постоянство обязательно и где явное задание идентификатора по крайней мере очень желательно.
Вот я и прошу уже вроде раз пятый людей. которые пишут про автоматическое назначение, привести примеры и более внятно аргументировать свою мысль. А то только и слышу "было бы круто", "такое часто нужно", а потом все как-то замолкают...
[...] А>>В твоём же случае, когда тебе понадобиться добавить очередной продукт, придётся обшарить все модули с целью узнать следующее незанятое значение TYPE. А их может быть несколько больше, чем один.
R>Это зависит от идентификатора класса. Если это например название элемента в XML-файле, то не придётся лазить, что бы найти следующий неиспользованный идентификатор. Потомучто это уже проектировщик решит, что элемент называется, например, "person". R>Или, если например, если идентификаторы связаны с каким-то протоколом. То тоже не придётся лазить, уже известно, что поддерживаем новый тип с кодом, например, 47.
Да-да, я совсем забыл, проектировщики имеют уникальную память и никогда не ошибаются, а ситуации, когда протокол 47 (элемент "person") уже используются абсурдны и смешны.
R>>>Там нет возможности нагружать эту инфроструктуру дополнительной функциоанльностью. То о чём я говорю — своего рода метаинформация или рефлекшн — и соответственно код на более высоком уровне. А>>Вот тут хотелось бы поподробнее. Смысл фабрики — сокрытие типов. Откуда возьмётся информация?
А>>
Какое это имеет отношение к фабрике классов?
Кстати, хотелось бы увидеть реализацию HeaderFactory::IsSimpleType(const std::string&)
R>Хотя, конечно, метод IsSimpleType() можно вынести в IHeader, а его реализацию в Header<>, тогда будет работать как ты хочешь.
При этом от твоих метаклассов не останется совсем ничего.
R>>>Хотя, возможно, мой класс фабрики можно относледовать от класса Loki::Factory, что бы заюзать часть функциональности. А>>)))))
R>Не понимаю, чего смешного
А вот
[...] А>>Резюмируя: к Loki::Factory добавлено две примочки, одна из которых может быть полезна при условии, что реализация продуктов сконцентрирована в очень небольшом числе модулей, а вторая просто бессмыслена. А>>)
R>Мне лично, она не кажется бессмысленной. Я применял такое решение на практике. И получал от него вполне практическую выгоду.
Повторюсь, хотелось бы увидеть реализацию HeaderFactory::IsSimpleType().
P.S.: Смайлики так и не заработали. Коды тоже отвалились.
P.P.S.: Автоинкремент идентификатора типа — полный бред. Тут я на удивление солидарен.
R>>Это зависит от идентификатора класса. Если это например название элемента в XML-файле, то не придётся лазить, что бы найти следующий неиспользованный идентификатор. Потомучто это уже проектировщик решит, что элемент называется, например, "person". R>>Или, если например, если идентификаторы связаны с каким-то протоколом. То тоже не придётся лазить, уже известно, что поддерживаем новый тип с кодом, например, 47. А>Да-да, я совсем забыл, проектировщики имеют уникальную память и никогда не ошибаются, а ситуации, когда протокол 47 (элемент "person") уже используются абсурдны и смешны.
Когда я применял такое решение. Для улутшения памяти разработчиков я сделал примерно так:
struct IHeader
{
...
// тут добавил развёрнутый комментарий по поводу назначения/изменения кодовenum TYPE
{
TYPE1 = 1,
TYPE2 = 2,
TYPE3 = 3
};
...
};
struct Header1 : Header<Header1>
{
static const int TYPE = IHeader::TYPE1;
};
с++ всё таки достаточно мощный язык для решения подобного рода проблем.
R>>>>Там нет возможности нагружать эту инфроструктуру дополнительной функциоанльностью. То о чём я говорю — своего рода метаинформация или рефлекшн — и соответственно код на более высоком уровне. А>>>Вот тут хотелось бы поподробнее. Смысл фабрики — сокрытие типов. Откуда возьмётся информация?
А>>>
К фабрике классов никакого. Но это имеет отношение к той инфраструктуре, которую я предствил в исходном посте, и которая представляет из себя фабрику классов совмещённую неким рефлекшном для классов-продуктов.
А>Кстати, хотелось бы увидеть реализацию HeaderFactory::IsSimpleType(const std::string&)
Я так понимаю, что тут опечатка, и вместо const std::string& должен быть int?
Если быть полностью последовательным, то так:
Здравствуйте, remark, Вы писали:
R>Мне на ум, исходя из моего опыта использования фабрик и вообще если подумать, приходят только варианты, где (1) это постоянство обязательно и где явное задание идентификатора по крайней мере очень желательно.
R>Вот я и прошу уже вроде раз пятый людей. которые пишут про автоматическое назначение, привести примеры и более внятно аргументировать свою мысль. А то только и слышу "было бы круто", "такое часто нужно", а потом все как-то замолкают...
Бывает, что и нужно. Полгода назад была у меня такая задачка. Фабрика создает как обьекты с известными id (которые жестко прошиты в протокол), так и другие объекты, которые используются при обработке и формировании результата, и соответственно не имеют реальных сlass-id.
Да, их можно и создавать напрямую (через new ClassName), но через фабрику было проще, однообразнее. Кроме того, фабрика являлась владельцем всех созданных ею обьектов, некоторые обьекты могли существовать только в единственном экземпляре и в добавок еще и самодельный rtti был.
Правда, ту либу я не считаю написанной "по рекомендациям лучших собаководов"
Здравствуйте, BitField, Вы писали:
BF>Здравствуйте, remark, Вы писали:
R>>Мне на ум, исходя из моего опыта использования фабрик и вообще если подумать, приходят только варианты, где (1) это постоянство обязательно и где явное задание идентификатора по крайней мере очень желательно.
R>>Вот я и прошу уже вроде раз пятый людей. которые пишут про автоматическое назначение, привести примеры и более внятно аргументировать свою мысль. А то только и слышу "было бы круто", "такое часто нужно", а потом все как-то замолкают...
BF>Бывает, что и нужно. Полгода назад была у меня такая задачка. Фабрика создает как обьекты с известными id (которые жестко прошиты в протокол), так и другие объекты, которые используются при обработке и формировании результата, и соответственно не имеют реальных сlass-id. BF>Да, их можно и создавать напрямую (через new ClassName), но через фабрику было проще, однообразнее. Кроме того, фабрика являлась владельцем всех созданных ею обьектов, некоторые обьекты могли существовать только в единственном экземпляре и в добавок еще и самодельный rtti был. BF>Правда, ту либу я не считаю написанной "по рекомендациям лучших собаководов"
Ну это хотя бы первое упоминание о реальном применении
А как назначались идентификаторы таким классам и как из можно было получить в коде, т.е.
Фабрика не является синглетоном и управляет временем жизни обьектов, являясь их владельцем.
Возможно, применение shared_ptr/intrusive_ptr было-бы выходом получше, но при непродолжнительных сессиях с малым числом создаваемых обьектов (до 5000) было удобнее уничтожать их одним махом.
Был синглетон-регистратор, который регистрировал классы
class Factory
{
public:
class Registrator
{
public:
int RegisterWithId(int id, ClassDesc desc);
int RegisterWithoutId(ClassDesc desc)
{
return RegisterWithId(NewId(), desc)
}
//...
};
...
}
структура ClassDesc содержала указатели на ф-ции создания, удаления и клонирования экземпляров класса.
У каждого класса было статическое поле int m_classId и static getter к нему. На них же строился велосипедный rtti.
Все это было завернуто в шаблоны и макросы типа DECL_ACTION_WITH[OUT]_ID / IMPL_ACTION
А вообще -- повторюсь -- та либа не была написана "по рекомендациям лучших собаководов"(самодельный rtti и type-switch в нескольких местах). Но наверное все-же была получше, чем та, на идеях которой была основана( 3000 строчные свитчи -- это нечто )
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Аноним, Вы писали:
R>>>Это зависит от идентификатора класса. Если это например название элемента в XML-файле, то не придётся лазить, что бы найти следующий неиспользованный идентификатор. Потомучто это уже проектировщик решит, что элемент называется, например, "person". R>>>Или, если например, если идентификаторы связаны с каким-то протоколом. То тоже не придётся лазить, уже известно, что поддерживаем новый тип с кодом, например, 47. А>>Да-да, я совсем забыл, проектировщики имеют уникальную память и никогда не ошибаются, а ситуации, когда протокол 47 (элемент "person") уже используются абсурдны и смешны.
R>Когда я применял такое решение. Для улутшения памяти разработчиков я сделал примерно так:
R>
R>struct IHeader
R>{
R>...
R>// тут добавил развёрнутый комментарий по поводу назначения/изменения кодов
R>enum TYPE
R>{
R> TYPE1 = 1,
R> TYPE2 = 2,
R> TYPE3 = 3
R>};
R>...
R>};
R>struct Header1 : Header<Header1>
R>{
R> static const int TYPE = IHeader::TYPE1;
R>};
R>
R>с++ всё таки достаточно мощный язык для решения подобного рода проблем.
Твоё сообщение от 18.03.06 20:14
8<----------------------
Вопрос спорный. То, о чём говоришь ты, как раз называют плохо расширяемым дизайном. Когда в одном месте много чего-то и это место надо постоянно править.
8<----------------------
Политика двойных стандартов?
Впрочем, я никогда не говорил, что саморегистрацию абсолютно бесполезная штука. Она-то как раз может быть полезна в ряде случаев. Далеко не всегда, но в ряде.
А>>Какое это имеет отношение к фабрике классов?
R>К фабрике классов никакого. Но это имеет отношение к той инфраструктуре, которую я предствил в исходном посте, и которая представляет из себя фабрику классов совмещённую неким рефлекшном для классов-продуктов.
Зачем плодить таких "совмещённых" монстров? Не лучше ли иметь мух отдельно от котлет?
А>>Кстати, хотелось бы увидеть реализацию HeaderFactory::IsSimpleType(const std::string&)
R>Я так понимаю, что тут опечатка, и вместо const std::string& должен быть int?
Отнюдь. Именно неинтегральный тип. Это проблема? Впрочем, забей, это не имеет значения.
[...]
Вроде прояснилось.
Насколько я понял, речь идёт о динамическом определении свойств типов по идентификатору типа.
Т.е. доступность информации о конкретном типе в рантайме.
Решение данной задачи ты интегрируешь в фабрику классов, которая создана для решения задачи сокрытия информации о конкретном типе.
В таком случае, не кажется ли тебе этот выбор несколько странным? Зачем из двух решений взаимноисключающих задач сооружать монструозную "инфраструктуру"?
Получилось что-то вроде телескопа, вмонтированного в белую трость для слепых. Бесполезно расширенная функциональность.
Re[9]: Саморегистрация классов в фабрике
От:
Аноним
Дата:
21.03.06 18:52
Оценка:
Ну раз уж я тут...
Здравствуйте, BitField, Вы писали:
BF>Здравствуйте, remark, Вы писали:
R>>Мне на ум, исходя из моего опыта использования фабрик и вообще если подумать, приходят только варианты, где (1) это постоянство обязательно и где явное задание идентификатора по крайней мере очень желательно.
R>>Вот я и прошу уже вроде раз пятый людей. которые пишут про автоматическое назначение, привести примеры и более внятно аргументировать свою мысль. А то только и слышу "было бы круто", "такое часто нужно", а потом все как-то замолкают...
BF>Бывает, что и нужно. Полгода назад была у меня такая задачка.
[...]
Спорю на тонну бачей, что на самом деле задача была как раз не такая. А именно, вовсе не требующая решения в виде фабрики классов с автоинкрементом ид класса. (ибо таких) Выкатывай тз, готовь бабасы. ))
Не самое удачное решение предлагается в качестве доказательства полезности кривого подхода. Я не противник кривых подходов. Теория теорией, а на практике приходится делать разные стыдные вещи.
Тем не менее, эти нехорошие вещи не стоит использовать для демонстрации полезности изначально кривого механизма.
Почувствуй свою ответственность, наконец. Вот прочитает ремарк твой пост и уволит всю армию своих подчинённых нах ни за член собачий. Бо они не используют таких "решений". Ты их кормить будешь? ))
R>>struct IHeader
R>>{
R>>...
R>>// тут добавил развёрнутый комментарий по поводу назначения/изменения кодов
R>>enum TYPE
R>>{
R>> TYPE1 = 1,
R>> TYPE2 = 2,
R>> TYPE3 = 3
R>>};
R>>...
R>>};
R>>struct Header1 : Header<Header1>
R>>{
R>> static const int TYPE = IHeader::TYPE1;
R>>};
R>>
R>>с++ всё таки достаточно мощный язык для решения подобного рода проблем. А>Твоё сообщение от 18.03.06 20:14 А>8<---------------------- А>Вопрос спорный. То, о чём говоришь ты, как раз называют плохо расширяемым дизайном. Когда в одном месте много чего-то и это место надо постоянно править. А>8<---------------------- А>Политика двойных стандартов?
Ну вот именно, что вопрос спорный. Я лишь говорю, у каждой медали есть 2 стороны. Можно сделать так, можно сделать так. Так решишь одну проблему, так другую.
А>Впрочем, я никогда не говорил, что саморегистрацию абсолютно бесполезная штука. Она-то как раз может быть полезна в ряде случаев. Далеко не всегда, но в ряде.
R>>К фабрике классов никакого. Но это имеет отношение к той инфраструктуре, которую я предствил в исходном посте, и которая представляет из себя фабрику классов совмещённую неким рефлекшном для классов-продуктов. А>Зачем плодить таких "совмещённых" монстров? Не лучше ли иметь мух отдельно от котлет?
Мне кажется, что тут всё нормально. Основа обоих сервисов — хранение списка метаклассов — это база — на основе этого работает и фабрика и другие сервисы.
А>>>Кстати, хотелось бы увидеть реализацию HeaderFactory::IsSimpleType(const std::string&)
R>>Я так понимаю, что тут опечатка, и вместо const std::string& должен быть int? А>Отнюдь. Именно неинтегральный тип. Это проблема? Впрочем, забей, это не имеет значения.
Нет, проблемы это абсолютно не представляет. Просто в примере. который я привёл идентификаторы — числа.
А>[...] А>Вроде прояснилось. А>Насколько я понял, речь идёт о динамическом определении свойств типов по идентификатору типа. А>Т.е. доступность информации о конкретном типе в рантайме. А>Решение данной задачи ты интегрируешь в фабрику классов, которая создана для решения задачи сокрытия информации о конкретном типе. А>В таком случае, не кажется ли тебе этот выбор несколько странным? Зачем из двух решений взаимноисключающих задач сооружать монструозную "инфраструктуру"? А>Получилось что-то вроде телескопа, вмонтированного в белую трость для слепых. Бесполезно расширенная функциональность.
Не согласен. По-моему, всё гармонично. Я лично это применял. Получилось очень красиво и функционально, лаконично и с нулевым дублированием.
R>Ассоциировался потом с классом? Что бы его можно было использовать через ActionA::GetClassID() ?
int ActionA::m_classId = Factory::Registrator::GetInstance().RegisterWithId(actionA, NormalActionDesc<ActionA>());
//actionA -- из энума известных протоколов. int ActionB::m_classId = Factory::Registrator::GetInstance().RegisterWithoutId(NormalActionDesc<ActionB>());
Здравствуйте, Аноним, Вы писали:
А>Спорю на тонну бачей, что на самом деле задача была как раз не такая. А именно, вовсе не требующая решения в виде фабрики классов с автоинкрементом ид класса. (ибо таких) А>) Выкатывай тз, готовь бабасы. А>)))
Не могу, NDA
Обрати внимание, что существовали классы с известным ID (забитым в структуру протокола нижнего уровня) -- для их создания пригодна обычная фабрика без автоинкремента и со статическим массивом (даже не мапой, ибо id у таких классов < 256) указателей на креаторы.
А вот с определенными в библиотеке классы удобнее было работать именно так (пусть даже при создании иногда приходилось даункастить).
Из плюсов: однообразная работа со всеми классами, отсутсвие контроля за тх временем жизни -- ибо обьект живет, пока жива фабрика-владелец. Кроме того, защита от сохранения обьекта, созданного на стеке (сtor/dtor у всех классов, кроме абстрактного базового -- protected). Помимо всего прочего, примение фабрики с increment-id было вызвано использованием самодельного rtti. (вот это один из главных минусов той либы)
А>Не самое удачное решение предлагается в качестве доказательства полезности кривого подхода. Я не противник кривых подходов. Теория теорией, а на практике приходится делать разные стыдные вещи. А>Тем не менее, эти нехорошие вещи не стоит использовать для демонстрации полезности изначально кривого механизма.
Я не привожу свое решение "в качестве доказательства полезности". Я привожу его именно как пример использования фабрики с increment-id. О полезности такого подхода нужно судить в каждом конкретном случае...
А вообще -- согласен, кривовато. Вполне можно было попробовать обойтись и без фабрики с increment-id. Dозможно, другие решения были бы проще/полезнее/оптимальнее.