![]() |
Модераторы: Partizan, gambit |
![]() ![]() ![]() |
|
Vyacheslav |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
Если в .NET встроенные средства для реализации паттерна "Фабрика классов"
-------------------- С уважением, Вячеслав Ермолаев |
|||
|
||||
Borisff2003 |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 198 Регистрация: 26.2.2004 Где: г. Уфа Репутация: нет Всего: 1 |
--------------------
Лень, двигатель прогресса |
|||
|
||||
Vyacheslav |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
То что там, пример довольно примитивного варианта фабрики, причем в его стандартном исполнении. А где же использование возможностей Атрибутов и Отражения?
-------------------- С уважением, Вячеслав Ермолаев |
|||
|
||||
Domestic Cat |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5452 Регистрация: 3.5.2004 Где: Dallas, US Репутация: 9 Всего: 172 |
Вообще-то паттерн - это не жесткая структура, загнать к-л паттерн в конкретную реализацию и сказать что это он и есть в конечном варианте нельзя. Сам по себе паттерн писать так же бессмыссленно как пытаться отделить полиморфизм от класса. Паттерн - это совокупность связей / взаимоотношений твоих объектов, каким образом создать средства для его реализации??? И при чем тут аттрибуты и рефлекшн???? -------------------- |
|||
|
||||
Vyacheslav |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
Ну спасибо за азы. Бестолковые, между прочим. Ну уж никак не думал, что "релизовать паттерн" воспримется как "написать паттерн".
Это то же кстати одно из определений паттерна -------------------- С уважением, Вячеслав Ермолаев |
|||
|
||||
[Last]Wizard |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 113 Регистрация: 20.7.2004 Где: Минск, Беларусь Репутация: 4 Всего: 10 |
Вот именно, ничего не изобретая! Написать паттерн можно просто механически, зная, как он реализуется, не нужно думать над тем, как спроектировать классы, и пр. Ведь не зря же эти паттерны называются ПАТТЕРНАМИ ПРОЕКТИРОВАНИЯ, а не ПРОГРАММИРОВАНИЯ! |
|||
|
||||
Vyacheslav |
|
||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
Приехали. Абстрактная Фабрика - паттерн, порождающий объекты Предоставляет интерфейс для создания семейств взаимосвязанных или взаимозависимых объектов, не специфирую их конкретных классов Абстрактная Фабрика очень часто реализуется с помощью патерна Factory Method или еще его называют Virtual Constuctor В С++ Virtual Constuctor либо имитируется с помощью switch или if, что довольно примитивно и требует при добавлении нового класса вносить изменение в класс Фабрики, либо с помощью map-таблицы сожержащий некий ключ(например текстовое имя ) и указатель на функцию, создающую объект класса, соответсвующего ключу. При этом дополнительно требуется перед использованием фабоики, провести процедуру регистрации класса, но при этом фабрика соверршено становится независима от классов, объекты которых она создает. В .NET имеется куча мета-информации и вполне врзможно создание класса по параметру Что первое приходит в голову, так это примерно вот это (на первый взгляд, ибо я только в начале .NET)
Добавлено @ 13:31
Согласен, но реализация паттерна(имеется в виду дизайн) на конкретном языке ( и платформе ) может быть различна, не говоря уж о квалификации ![]() -------------------- С уважением, Вячеслав Ермолаев |
||||||
|
|||||||
Vyacheslav |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
Кстати, если заменим enum на String, а при создании объекта Fabric будем передоватьимя сборки, то получаем фабрику классов, совершеено независимую от классов, которые она будет создавать
Но, естесвенно, это всего лишь первый набросок, поэтому и возник вопрос. Может кто уже давно сделал лучше. -------------------- С уважением, Вячеслав Ермолаев |
|||
|
||||
Domestic Cat |
|
||||||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5452 Регистрация: 3.5.2004 Где: Dallas, US Репутация: 9 Всего: 172 |
Гоф цитировать мне не надо, а лучше взглянуть на класс диаграмму для этого паттерна. И узнать, что все-таки у них каждая конкретная фабрика - сабкласс AbstractFactory знает о тех объектах, которые она должна произвести.
Интересно, и где это в абстрактной фабрике свичи, ифы или мапы? Хотя бы на пример в Гамме посмотри...
Ничего особо хорошего в этом методе нет, поскольку рефлекшн - не самый быстрый способ создать класс. Никто конечно не мешает таким образом реализовать паттерн. Только вот он никоим образом не будет подходить всем и вся. Потому, что основная мотивация абстрактной фабрики (смотреть опять-таки ГоФ)
Заметь - нигде не сказано, что фабрика не должна о чем-то знать. СИСТЕМА не должна знать. Главная цель - иметь возможность легко создавать группы взаимозаменяемых объектов, причем с минимальным вмешательством в систему. И способы, описанные в Дизайн Паттернах хороши и тем, что они служат поставленной задаче, и своей простотой. И лично я не вижу смысла в создании фабрики, которая не знает, чего она производит. Потому что в лучшем случае это даст выигрыш в пару строк кода, но зато создаст серьезный оверхед из-за рефлекшна. Возможно, ее потом и можно реюзать, но придется возиться с рефлекшном.
Если тебя не поняли - это отчасти и твоя вина. В английском техническом языке "to realize" означает "make real or concrete; give reality or substance to; "our ideas must be substantiated into actions"". Весьма странные слова для модератора. -------------------- |
||||||||||||
|
|||||||||||||
[Last]Wizard |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 113 Регистрация: 20.7.2004 Где: Минск, Беларусь Репутация: 4 Всего: 10 |
Vyacheslav, если тебе нужна фабрика, которая
то посмотри Activator.CreateInstance(). Хотя до паттерна "Абстрактная фабрика" это не дотягивает. |
|||
|
||||
Vyacheslav |
|
||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
То что одним из возможных вариантов реализации Абстрактной Фабрики явлется реализация посредством Фабричного Метода - это, надеюсь возражений не вызывает? Если вызывает- отсылаю к Гамму. Смотрим Фабричный метод. Там используется класс Creator, который может содержать параметризованный фабричный метод Так если Вы заглянете в книжку, то увидидите то, что в реализации для этого метода на С++ используется конструкция if.
![]() Это во первых. А во вторых, надо понимать, что там даны всего лишь примеры для иллюстрации того, как реализация паттерна будет выглядеть на конкретном языке и для определенного примера. К тому же качество кода в примерах весьма посредственное, но другого там и не требовалось. Ибо цель примеров - донести идею, а не научить программировать. И естественно для С++ это можно реализовать более удачно например так
Ок. В таком случае подскажите, как я должен был сформулировать вопрос, что бы Вы не поняли что собирался не описывать паттерн, а используя уже имеющиеся описания, "реализовать"(извините другого слова подобрать не смог) его применительно к решению конкретной задачи и конкретной языковой среды? -------------------- С уважением, Вячеслав Ермолаев |
||||||
|
|||||||
Domestic Cat |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5452 Регистрация: 3.5.2004 Где: Dallas, US Репутация: 9 Всего: 172 |
Вызывает. это другой паттерн, никак не абстрактная фабрика.
это зависит от задачи, а о конкретной задаче пока разговора не было. Если действительнo в runtime неизвестно, объекты каких классов надo создать, тo да, такой вариант имеет место быть. Хотя oбъект можнo создавать не по аттрибуту, а по типу или стринговому названию класса - как подсказал [Last]Wizard. http://msdn.microsoft.com/library/default....stancetopic.asp Так прощe. -------------------- |
||||
|
|||||
Vyacheslav |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
Спасибо. Это как раз первое, за что я зацепился. Это естественно не фабрика, другое дело - это, по всей видимости, можно эффективно использовать при создании фабрики -------------------- С уважением, Вячеслав Ермолаев |
||||
|
|||||
Vyacheslav |
|
||||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
[/code]
Дедо в том, что завязка непосредственно на тип просто перемещает if'ы (или что то вместо них) в другое место. Мне приходит откуда-то некая информация , по которой я должен созлать экземпляр класса. Соответсвенно мне все равно придется где то иметь код, который доджен сопоставить значение этой информации с типом. Естественно хочется, что бы при добавлении нового класса, не требоавалось лезть туда и снова что то добавлять. В идеале , нужно сделать так, что бы вообще не требовалась перекомпиляция основной приложения. Достаточно было бы добавить класса в библиотеку (в дополнительную сборку). Во всяком случае такой код уже работает Требуемый экземпляр класса создается на основании значения свойства MsgType класса CMessage
При необходимости добавить еще одни класс(CTestExecutor)например достаточно добавить
В резулбтате приминительно к моему случаю обработка приходящих сообщений выливается в
-------------------- С уважением, Вячеслав Ермолаев |
||||||||
|
|||||||||
Domestic Cat |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5452 Регистрация: 3.5.2004 Где: Dallas, US Репутация: 9 Всего: 172 |
Ну в такой ситуации - я согласен. Если б сначала написал о задаче, и разговора б не было
![]() -------------------- |
|||
|
||||
Vyacheslav |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
Возможно. То что я реализовал - это первое, что пришло мне в голову при поверхностном обзоре возможностей .NET. А я в нем только с начала марта. А я по опыту знаю, что первое пришедшее решение далеко не всегда эффективно. С другой стороны иммитировать виртуальный конструктор средствами pure C++ при наличии такового( CreateInstance) в среде выглядит довольно глупо. Тем более, IMHO то что написанное на чистом С++ и STL выглядит изящнее, чем его эквивалент на managed C++. Отсюда и возник первоначальный вопрос
Добавлено @ 10:44 Вот чертов managed C++ Чтобы в pure С++ закешировать список типов мне достаточно было указать static Вместо
использовать
но в managed C++ это не проходит. Ругается компилятор. Теперь придется что то изобретать дополнительно. -------------------- С уважением, Вячеслав Ермолаев |
||||
|
|||||
Vyacheslav |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
Во как получилось. В полном противоречии со стандартом С++
![]()
-------------------- С уважением, Вячеслав Ермолаев |
|||
|
||||
arilou |
|
|||
![]() Великий МунаБудвин ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2646 Регистрация: 15.7.2004 Где: город-герой Минск Репутация: 21 Всего: 61 |
Честно говоря, просмотрев эту ветку, у меня возник немного другой вариант. Напишу на C#, т.к. мне это ближе. Для моей реализации необходимо 2 допущения:
1) Каждому классу, наследующемуся из MyApp.MyNamespace.MyMessage соответствует класс MyMessageDescendantExecutor, где MyMessageDescendant - это имя класса-потомка MyMessage. Класс MyMessageDescendantExecutor должен находиться в том же namespace, что и MyMessageDescendant. 2) Все Executor'ы соответствуют интерфейсу IExecutor
В результате велосипед не изобретен, пользуемся стандартными средствами. Как написано в комментарии, можно кэшировать не типы executor'ов, а инстансы. Надеюсь, что это имеет смысл. Таким же образом решаются задачи этого уровня. P.S. 1) Не заметил, писал ли кто-нить, что Activator.CreateInstance в сочетании с информацией о типах реализует абстракную фабрику классов, т.е. такую, которая умеет создавать инстансы любых типов. 2) Добавление других сообщений и executor'ов происходит с минимальными издержками - добавляешь 2 класса, и вуаля - все работает ![]() Это сообщение отредактировал(а) arilou - 16.3.2005, 20:35 |
|||
|
||||
Vyacheslav |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
Тут оказалась скрыта другая часть задачи. Дело в том, что при таком подходе проблема просто перетечет в PeekIncoming(). От клиента приходит массив байтов, с помощью которого заполняется CMessage. Если использовать Ваш подход, то мне все равно на основании данных, содержащихся в массиве необходимо создать соответсвующий этим данным класс XXXMessage, а затем используя имя класса создать экземпляр класса XXXMessageExecutor. При этом все равно вопрос остается открытым : нужно приходящим данным сопоставить соответствущий класс( теперь не Executor, а Мessage) и создать его экземпляр.
Здесь есть один неприятный момент: клиентская часть уже исторически унаследована, может работать на различных платформах и переделать ее таким образом, что бы она вместо линейного массива данных передавала непосредственно объект, нельзя. Интерфейс и протокол обмена определен и зафиксирован и моя программа дожна обрабатывать сообщения, поступающие от него. Проблема в том, что их в общем случае очень много, а я должен обрабатывать ограниченную часть, но никто не гарантирует, что после некоторого времени, потребуется зайдействовать дополнительные команды из этого набора. Также не исключается возможность, что добавлять обработки новых сообщения буду не я и даже не моя фирма. Поэтому и хочется по максимому облегчить процесс добавления В моем случае при этом добавляется один класс и, я пока не силен в .NET, мне кажется при внесении небольших изменений, можно дело поставить таким образом, что добавление новых классов будет производится просто посредством подмены некоторой загружаемой библиотеки (сборки?) -------------------- С уважением, Вячеслав Ермолаев |
|||
|
||||
arilou |
|
||||||||
![]() Великий МунаБудвин ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2646 Регистрация: 15.7.2004 Где: город-герой Минск Репутация: 21 Всего: 61 |
Наверняка массив байт содержит в начале некий заголовок, который указывает на тип сообщения. Я прав? Если так, то можно сделать следующее (в целях упрощения заголовок будет типа byte, т.е. имеем 255 различных типов сообщений):
Мой приведенный выше пример можно расширять следующим образом: 1) Можно редактировать исходный код - добавлять новые сообщения и executor'ы - это при условии, что есть доступ к исходникам 2) Выносим Message и IExecutor в отдельную общую сборку. В MessageRepository.Init заружаем все сборки из определенного каталога (например, components), перебираем все загруженные сборки, выполняем ту же процедуру (см. метод Init) для каждого типа, удовлетворяющего условию. Разработка дополнительных типов сообщений потребует от других фирм поставить референс на Вашу общую сборку (там, где определен класс Message и интерфейс IExecutor), реализовать их и поместить в каталог components, откуда ваша программа благополучно считает их в repository. Наедюсь, что это Вам поможет. ![]() P.S. Кстати, таким же образом можно реализовать и загрузку и сопоставление всех Executor'ов. P.P.S Таким образом, функция PeekIncoming может выглядеть следующим образом:
Это сообщение отредактировал(а) arilou - 17.3.2005, 13:05 |
||||||||
|
|||||||||
Vyacheslav |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
Насчет типа сообщения Вы правы. Только сначала идет длина, потом тип.
Насчет же всего прочего, я примерно так и делал за некоторым исключением. Во первых я таким образом создавал не Message, а Executor
Во-вторых, основное отличие, как я понял в том, что бы не перебирать каждый раз все типы сборки, а предварительно закэшировать в Hashtable только те типы, которые впоследствии потребуются. Это в высшей степени разумно. Я обязательно воспользуюсь этим. А теперь вопрос. Можно ли заменить в принципе это десериализацией при условии при фиксированном и неизменном формате присылаемых данных? Ведь приведенный вами код в принципе этим и является
-------------------- С уважением, Вячеслав Ермолаев |
||||
|
|||||
arilou |
|
|||
![]() Великий МунаБудвин ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2646 Регистрация: 15.7.2004 Где: город-герой Минск Репутация: 21 Всего: 61 |
В принципе
Не могу придумать, чем тут поможет десериализция в том понятии, в котором она используется в .NET'e, ведь приходит некий поток байтов, который же не является бинарным отображением объекта? Если бы это были какие-нить символьные данные, то можно было бы через XSL превращать их в XML-сериализованное представление объекта, и десериализовать сам объект. На выходе получался бы экземпляр Message. Скорее, я бы определил этот метод (ReadFromStream) в базовом классе, а в потомках бы из байтового массива на входе доставал бы данные и записывал в поля и свойства. Не зная специфики принимаемых данных ничего более умного предложить не могу ![]() |
|||
|
||||
Vyacheslav |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
Я не стал использовать метод. Просто в конструктор тупо передаю массив и от хранится как поле класса. Для общих свойств(тип, длина итд) определил свойства, которые читают-записывают прямо из массива.
-------------------- С уважением, Вячеслав Ермолаев |
|||
|
||||
arilou |
|
|||
![]() Великий МунаБудвин ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2646 Регистрация: 15.7.2004 Где: город-герой Минск Репутация: 21 Всего: 61 |
Логично ![]() |
|||
|
||||
Vyacheslav |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2124 Регистрация: 25.3.2002 Где: Москва Репутация: 2 Всего: 59 |
Я это как раз и делаю
![]()
Меня радует, что после обсуждения мы пришли почти к единому знаменателю. А значит можно сказать, что решение с большой долей вероятности работоспособно. В принципе моя цель в этом и заключалась: убедится в применимомти или непригодности решения -------------------- С уважением, Вячеслав Ермолаев |
|||
|
||||
arilou |
|
|||
![]() Великий МунаБудвин ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 2646 Регистрация: 15.7.2004 Где: город-герой Минск Репутация: 21 Всего: 61 |
Ну тогда топик действительно можно закрывать
![]() |
|||
|
||||
![]() ![]() ![]() |
Прежде чем создать тему, посмотрите сюда: | |
|
Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов. Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :) Так же не забывайте отмечать свой вопрос решенным, если он таковым является :) Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |