design patterns
От: Аноним  
Дата: 07.10.06 12:21
Оценка:
Добрый день!

Подскажите, пожалуйста, как применить design patterns в следующем случае:

Имеется базовый (абстрактный) класс назовем его BaseMessage и несколько наследуемых от него классов. Эти классы предназначены для хранения сообщений, получаемых в текстовом виде и содержащих набор определенных информационных полей из этого текстового сообщения. Различные типы текстовых сообщений имеют различные поля, которые порою значительно отличаются друг от друга и могут иметь иерархическую структуру. Необходимо спроектировать эти классы таким образом, чтобы объекты-сообщения можно было сохранять в различных форматах: текст, xml, различные базы данных (firebird, mysql…).
Разработка осуществляется на C#. Пока я ввел в базовый класс объект (типа interface) ISaver, в котором присутствует метод Save(BaseMessage message), в котором в качестве аргумента указатель на сообщение, которое нужно сохранить. Виртуальный метод класса BaseMessage также содержит метод Save без параметров, который вызывает метод этого интерфейсного объекта и указывая в качестве аргумента this.
Но как быть дальше с классами реализующими этот интерфейс (ISaver)– ума не приложу. Не хочется создавать классы Saver-ы для каждого формата, в котором нужно сохранять сообщения, и для каждого типа сообщения.
Как быть?
Re: design patterns
От: KolanT  
Дата: 07.10.06 16:31
Оценка:
Посмотри паттер Builder.
Re: design patterns
От: gyraboo  
Дата: 07.10.06 18:34
Оценка:
Здравствуйте, Аноним, Вы писали:

1. Иерархическая структура сообщений... Значит начинаем думать о структурном паттерне Composite.
2. Сохранение в разных форматах... Подойдет повденческий паттерн Visitor. На каждый сохраняемый формат заводишь свой визитор.

Кстати, оба паттерна идеально дополняют друг-друга.
Для парсинга сообщений при переводе их в объектную структуру подойдет Builder (логика создания объектов) и Director (непосредственно парсер).

А>Добрый день!


А>Подскажите, пожалуйста, как применить design patterns в следующем случае:


А>Имеется базовый (абстрактный) класс назовем его BaseMessage и несколько наследуемых от него классов. Эти классы предназначены для хранения сообщений, получаемых в текстовом виде и содержащих набор определенных информационных полей из этого текстового сообщения. Различные типы текстовых сообщений имеют различные поля, которые порою значительно отличаются друг от друга и могут иметь иерархическую структуру. Необходимо спроектировать эти классы таким образом, чтобы объекты-сообщения можно было сохранять в различных форматах: текст, xml, различные базы данных (firebird, mysql…).

А>Разработка осуществляется на C#. Пока я ввел в базовый класс объект (типа interface) ISaver, в котором присутствует метод Save(BaseMessage message), в котором в качестве аргумента указатель на сообщение, которое нужно сохранить. Виртуальный метод класса BaseMessage также содержит метод Save без параметров, который вызывает метод этого интерфейсного объекта и указывая в качестве аргумента this.
А>Но как быть дальше с классами реализующими этот интерфейс (ISaver)– ума не приложу. Не хочется создавать классы Saver-ы для каждого формата, в котором нужно сохранять сообщения, и для каждого типа сообщения.
А>Как быть?
Re[2]: design patterns
От: Аноним  
Дата: 07.10.06 20:37
Оценка: 5 (1)
Здравствуйте, gyraboo, Вы писали:

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


G>1. Иерархическая структура сообщений... Значит начинаем думать о структурном паттерне Composite.


Разве автор вопроса писал о вложенности сообщений?

G>2. Сохранение в разных форматах... Подойдет повденческий паттерн Visitor. На каждый сохраняемый формат заводишь свой визитор.


По-моему, Visitor тут _совсем_ не подходит.
Читаем "первоисточник":

Используйте паттерн посетитель, когда:
* в структуре присутствуют объекты многих классов с различными интерфейсами и вы хотите выполнять операции, зависящие от конкретных классов.


мы же хотим наоборот, выполнять операции общие для всех классов (сохранение). Ну и интерфейс примерно общий у всех классов, раз предок у них один.

* над объектами, входящими в состав структуры, надо выполнять разнообразные, не связанные между собой операции и вы не хотите "засорять" классы такими операциями. Посетитель позволяет обхединить родственные операции, поместив их в один класс. Если структура объектов является общей для нескольких приложений, то паттерн Посетитель позволит в каждое приложение включить только относящиеся к нему операции.


Над объектами нам надо выполнять одну и ту же операцию, связанную с другими такими же (сериализация).

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


Если мы вдруг захотим добавить сохранение в SQL или еще куда, придется менять интерфейсы по всем Посетителям. Посетитель в данном случае сведет на нет небогатую выгоду своего применения (оставшуюся от предыдущих двух пунктов)

G>Кстати, оба паттерна идеально дополняют друг-друга.

G>Для парсинга сообщений при переводе их в объектную структуру подойдет Builder (логика создания объектов) и Director (непосредственно парсер).

Билдер, он не только ведь для создания.
Мне кажется, он тут и поможет.


А>>Добрый день!


А>>Подскажите, пожалуйста, как применить design patterns в следующем случае:


А>>Имеется базовый (абстрактный) класс назовем его BaseMessage и несколько наследуемых от него классов. Эти классы предназначены для хранения сообщений, получаемых в текстовом виде и содержащих набор определенных информационных полей из этого текстового сообщения. Различные типы текстовых сообщений имеют различные поля, которые порою значительно отличаются друг от друга и могут иметь иерархическую структуру. Необходимо спроектировать эти классы таким образом, чтобы объекты-сообщения можно было сохранять в различных форматах: текст, xml, различные базы данных (firebird, mysql…).

А>>Разработка осуществляется на C#. Пока я ввел в базовый класс объект (типа interface) ISaver, в котором присутствует метод Save(BaseMessage message), в котором в качестве аргумента указатель на сообщение, которое нужно сохранить. Виртуальный метод класса BaseMessage также содержит метод Save без параметров, который вызывает метод этого интерфейсного объекта и указывая в качестве аргумента this.
А>>Но как быть дальше с классами реализующими этот интерфейс (ISaver)– ума не приложу. Не хочется создавать классы Saver-ы для каждого формата, в котором нужно сохранять сообщения, и для каждого типа сообщения.
А>>Как быть?

Эта задача называется сериализацией.
Мои предложения:
1. (рекомендуемое на первом этапе) Не заморачивайся заранее с тем, в какие форматы вруг потребуется сохранять сообщения. Сделай в базовом классе иерархии абстрактные методы SaveToFile() и RestoreFromFile() и реализуй их в каждом подклассе. Если вдруг чего потом переделать/добавить потом понадобится, потом подумаешь, какой паттерн лучше применить. По шагам надо, чтобы программа работала после каждого шага, чтобы заказчик не нервничал.
2. (стандартное) Воспользуйся стандартной сериализацией, предоставляемой средой. В частности XmlSerializer. При соблюдении опред. условий, сохранение/загрузку вообще самому писать не придется. Просто вызывать стандартные классы, которые упакуют все на винт и распакуют обратно.
3. (общее) Воспользоваться Builder. Т.е. каждый класс сообщения релизует пару Store/Restore(MyBuilder builder) (вместо Restore можно просто потребовать конструктор с аналогичніми параметрами), которые принимают объект билдер, интерфейс которого маскимально общ: SaveString(), SaveInteger(), RestoreString(), RestoreInteger() и т.п. Внутри Store/Restore пользуйся только этими методами билдера для сохранения своего состояния (сообщения). Потом релизуй один билдер, который делает все Store/RestoreString/Integer в файл. При необходимости потом реализуешь тот же общий интерфейс для XML случая, потом можно для SQL и т.п. При этом переписывать а тем более менять интерфейсы нигде не надо будет.
Re: design patterns
От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
Дата: 09.10.06 06:59
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Добрый день!


А>Подскажите, пожалуйста, как применить design patterns в следующем случае:


А>Имеется базовый (абстрактный) класс назовем его BaseMessage и несколько наследуемых от него классов. Эти классы предназначены для хранения сообщений, получаемых в текстовом виде и содержащих набор определенных информационных полей из этого текстового сообщения. Различные типы текстовых сообщений имеют различные поля, которые порою значительно отличаются друг от друга и могут иметь иерархическую структуру. Необходимо спроектировать эти классы таким образом, чтобы объекты-сообщения можно было сохранять в различных форматах: текст, xml, различные базы данных (firebird, mysql…).

А>Разработка осуществляется на C#. Пока я ввел в базовый класс объект (типа interface) ISaver, в котором присутствует метод Save(BaseMessage message), в котором в качестве аргумента указатель на сообщение, которое нужно сохранить. Виртуальный метод класса BaseMessage также содержит метод Save без параметров, который вызывает метод этого интерфейсного объекта и указывая в качестве аргумента this.
А>Но как быть дальше с классами реализующими этот интерфейс (ISaver)– ума не приложу. Не хочется создавать классы Saver-ы для каждого формата, в котором нужно сохранять сообщения, и для каждого типа сообщения.
А>Как быть?

Для примера Вы можете посмотреть как ведет себя механизм серилизации с использованием ISerializable интерфейса. Идея простая:

Таким образом в целом у Вас должно быть как минимум две сущности: сохраняемый объект и сохраняющий механизм.

Например:

public interface IPersistentObject
{
    IDictionary<string, object> GetObjectData();
}

public interface IPersister
{
    void Save(IDictionary<string, object> objectData, Stream s);
}
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: design patterns
От: Кирилл Лебедев Россия http://askofen.blogspot.com/
Дата: 09.10.06 08:03
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Как быть?


Я бы на Вашем месте подумал бы над тем: нельзя ли все эти сообщения свести к одной структуре данных. И если можно, то свел бы. Тогда бы и реализация ISaver упростилась бы, т.к. писать функции сохранение нужно будет только для одной структуры данных (пусть и в разные форматы). Насколько я понимаю, разница между сообщениями заключается только в данных. У них нет каких-то специфичных функций (за исключением аксессоров).
С уважением,
Кирилл Лебедев
Software Design blog — http://askofen.blogspot.ru/
Re[2]: design patterns
От: _FRED_ Черногория
Дата: 09.10.06 08:34
Оценка:
Здравствуйте, pt4h, Вы писали:

>Для примера Вы можете посмотреть как ведет себя механизм серилизации с использованием ISerializable интерфейса. Идея простая:



Идея имеет ряд существенных ограничений: попробуйте ниписать форматтер, сохраняющий сериализуемый объект даннмым методом в настраиваемый Xml или базу данных — не выйдет. А почему?
... << RSDN@Home 1.2.0 alpha rev. 652>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Re[3]: design patterns
От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
Дата: 09.10.06 08:38
Оценка:
Здравствуйте, _FRED_, Вы писали:

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


>>Для примера Вы можете посмотреть как ведет себя механизм серилизации с использованием ISerializable интерфейса. Идея простая:

_FR>…

_FR>Идея имеет ряд существенных ограничений: попробуйте ниписать форматтер, сохраняющий сериализуемый объект даннмым методом в настраиваемый Xml или базу данных — не выйдет. А почему?


Меня по началу испугала "широкая" иерархия сейверов в Ваше решение, но потом я присмотрелся и понял, что это решение более живое, что механизм, похожий на серилизцию (для несложных объектов он может пройти)...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: design patterns
От: _FRED_ Черногория
Дата: 09.10.06 08:50
Оценка: +1
Здравствуйте, pt4h, Вы писали:

>>>Для примера Вы можете посмотреть как ведет себя механизм серилизации с использованием ISerializable интерфейса. Идея простая:


_FR>>Идея имеет ряд существенных ограничений: попробуйте ниписать форматтер, сохраняющий сериализуемый объект даннмым методом в настраиваемый Xml или базу данных — не выйдет. А почему?


P>…механизм, похожий на серилизцию (для несложных объектов он может пройти)...


Может даже для сложных. Беда тут не в сложности объекта (сложность может быть практически любая), а в сложности формата данных.

P>Меня по началу испугала "широкая" иерархия сейверов …


Меня тоже :о)) На практика показывает, что в этом нет ничего страшного — "базовые" сейверы могут быть большими и сложными классами, но их ровно столько, сколько форматов сохранения, то есть минимум. То, что это количество в конечном итоге умножается на количество типов сообщений не так ужасно: эти классики маленькие, зачастую очень-очень простые. Если есть фабрика, которая их создаёт, то конечному пользователю, которому надо "вот это" "вот сюда", про них не должно быть даже ничего известно. НК тому же такой вариант позволяет просто и быстро, не затрагивая "соседние" сообщения и форматы где-то что-то подкрутить. и даже сильно подкрутить.

ЗЫ: Речь об этом
Автор: _FRED_
Дата: 07.10.06
... << RSDN@Home 1.2.0 alpha rev. 652>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Re[5]: design patterns
От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
Дата: 09.10.06 08:58
Оценка:
Здравствуйте, _FRED_, Вы писали:

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


>>>>Для примера Вы можете посмотреть как ведет себя механизм серилизации с использованием ISerializable интерфейса. Идея простая:


_FR>>>Идея имеет ряд существенных ограничений: попробуйте ниписать форматтер, сохраняющий сериализуемый объект даннмым методом в настраиваемый Xml или базу данных — не выйдет. А почему?


P>>…механизм, похожий на серилизцию (для несложных объектов он может пройти)...


_FR>Может даже для сложных. Беда тут не в сложности объекта (сложность может быть практически любая), а в сложности формата данных.


P>>Меня по началу испугала "широкая" иерархия сейверов …


_FR>Меня тоже :о)) На практика показывает, что в этом нет ничего страшного — "базовые" сейверы могут быть большими и сложными классами, но их ровно столько, сколько форматов сохранения, то есть минимум. То, что это количество в конечном итоге умножается на количество типов сообщений не так ужасно: эти классики маленькие, зачастую очень-очень простые. Если есть фабрика, которая их создаёт, то конечному пользователю, которому надо "вот это" "вот сюда", про них не должно быть даже ничего известно. НК тому же такой вариант позволяет просто и быстро, не затрагивая "соседние" сообщения и форматы где-то что-то подкрутить. и даже сильно подкрутить.


_FR>ЗЫ: Речь об этом
Автор: _FRED_
Дата: 07.10.06


Мне тоже ближе решения, которые предоставляются самим объектом (Message) или его помощником(Saver). Потому как решения основанные на едином формате (мета языке, разметке и т.д.) как правила заканчиваются поиском мест "куда бы воткнуть новый тип данных".
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: design patterns
От: denis miller Россия http://agile20.ru
Дата: 09.10.06 14:50
Оценка:
А>Имеется базовый (абстрактный) класс назовем его BaseMessage и несколько наследуемых от него классов. Эти классы предназначены для хранения сообщений, получаемых в текстовом виде и содержащих набор определенных информационных полей из этого текстового сообщения. Различные типы текстовых сообщений имеют различные поля, которые порою значительно отличаются друг от друга и могут иметь иерархическую структуру. Необходимо спроектировать эти классы таким образом, чтобы объекты-сообщения можно было сохранять в различных форматах: текст, xml, различные базы данных (firebird, mysql…).
А>Разработка осуществляется на C#. Пока я ввел в базовый класс объект (типа interface) ISaver, в котором присутствует метод Save(BaseMessage message), в котором в качестве аргумента указатель на сообщение, которое нужно сохранить. Виртуальный метод класса BaseMessage также содержит метод Save без параметров, который вызывает метод этого интерфейсного объекта и указывая в качестве аргумента this.
А>Но как быть дальше с классами реализующими этот интерфейс (ISaver)– ума не приложу. Не хочется создавать классы Saver-ы для каждого формата, в котором нужно сохранять сообщения, и для каждого типа сообщения.
А>Как быть?

отделить имплементацию нужно через Bridge (параллели лучше запрятать через Plugins)
иерархию через Composite.
по сохранению смотри в сторону Builder.

если чё звони в skype (syspo@mail.ru)
Re[6]: design patterns
От: gok Россия  
Дата: 10.10.06 18:53
Оценка:
Здравствуйте, pt4h, Вы писали:

P>Мне тоже ближе решения, которые предоставляются самим объектом (Message) или его помощником(Saver). Потому как решения основанные на едином формате (мета языке, разметке и т.д.) как правила заканчиваются поиском мест "куда бы воткнуть новый тип данных".


При создании конкретной пары Saver1 — Message1 все равно придется пробегать по дереву поддерживаемых типов данных.
Пример. Есть два типа сообщений, почти похожих, но операции проводятся, например, только для x,y,z:
Message1 {
    double timeStamp;
    double x;
    double y;
    double z
}
Message2 {
    double x;
    double y;
    double z
}

В фабрике при создании нужного Save-ра надо проверить Message на конкретный тип данных (Message1 или Message2), которые хорошо описать на мета языке:
</formats>
- <format name="txyz">
  <timestamp type="double">1</timestamp> 
  <xpulse type="double">2</xpulse> 
  <ypulse type="double">3</ypulse> 
  <zpulse type="double">4</zpulse> 
  </format>
- <format name="xyz">
  <xpulse type="double">1</xpulse> 
  <ypulse type="double">2</ypulse> 
  <zpulse type="double">3</zpulse> 
  </format>
</formats>

В этом плане проблема "куда воткнуть новый тип данных" остается:
Message3 {
double x;
double y;
double z
double speed;
}

Или все же этого можно избежать?
gok
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.