| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Системный анализ, проектирование и UML > ищу паттерн проектирования |
| Автор: CompWorm 9.12.2013, 23:11 |
| Привет! пытаюсь подобрать паттерн для решения такой задачи: к приложению подключаются сервисы в виде dll, а так же сценарии, тоже в виде dll. и те и другие реализованы в виде фабрики, т.е. отдают приложению объект, соответствующий интерфейсам IService, IScenario. объект IScenario должен уметь выполнять команды IService, но сценарий будет создаваться пользователями под некоторые сервисы, то есть сценарий будет полностью совместим лишь с некоторыми сервисами, для которых создавался. у сервисов могут быть как общеиспользуемые команды, так и специфические. нужно учитывать, что в новых версиях сервиса могут добавляться новые команды, и сценарий должен быть готов к этому. нужен паттерн для общения сервиса со сценарием. первая идея - создать в IScenario метод Object execute (String command, Object[] parameters) и list[] getSupportedCommands() не знаю что это за паттерн такой ))) тут проблема очевидна - код никак не подсказывает ни сколько параметров нужно передать для выполнения команды, ни их тип, ни наличие возвращаемого объекта, ни его тип. кроме того, списки команд для разработчика сценария тоже скрыты. контрактный паттерн тоже не очень понятно как тут применить: количество команд-методов класса заранее неизвестно... командный паттерн смотрится не лучше - сценарий может вернуть свои исполняемые объекты, но какой в этом смысл, если у многих сценариев есть одни и те же команды... идеи ? |
| Автор: ksnk 9.12.2013, 23:50 |
| Ну а чистосценарные решения не подходят? Поставить туда скриптовый язык достаточной продвинутости. lua или скажем javascript. Для любителей этого дела и php можно покрутить-пооблизываться. Ядрышко на скриптах, для объединения в едину кучу. Новый сервис - новый пакет скриптов с диктуемым ядром интерфейсом. |
| Автор: Lipetsk 10.12.2013, 08:52 |
биндинг можно написать свой |
| Автор: CompWorm 11.12.2013, 01:24 |
| ksnk, Lipetsk, тема не про LUA, а про паттерн. даже если я реализую всё через скрипты, вопрос про интерфейс общения сервиса со сценарием останется открытым. |
| Автор: Guinness 11.12.2013, 08:22 | ||
А что если создать объект Command?
В принципе, класс Argument можно разбить и преобразовать к ArgumentType. И хранить все это дело в map<ArgType, Object>. Но это всё для статически типизированных языков - тут приходится придумывать костыли, ну или я не слишком ещё искушен в написании нормальных программ. Вообще, тут сильно зависит от языка и технологий, которые используются. Наверняка, это можно как-то прикрутить с помощью скриптовых языков, но я это никогда не делал и потому не знаю об этом) |
| Автор: CompWorm 11.12.2013, 21:27 | ||||
Guinness, да, да, похоже на правду, но тут две проблемы я сразу вижу: 1) нет способа проверить совместимость сценария с сервисом. то есть сервис тут не знает, что умеет сценарий и просто бомбит его командами. в общем им понюхатся надо как-то )) 2) прикинь, на каждую команду по классу аргументов создавать придется... что-то громоздко выходит, не?
c++ для ориентировки)) я щас обжовываю другую мысль - сделать что-то типа контракта, но не в классической форме, так как уж очень макросы я не люблю, а в плюсах через них обычно предлагается. итак, идея создать общий для всех класс, аля абстрактный адаптер. он создается на стороне сервиса и инициализируется, условно, неким списком, описиваюшим команды и их аргументы, который получаем из сценария. в результате, из сервиса мы зовем
тут сигнатура bool makeSomeFun(int) заранее (compile-time) не прописана ни в Adapter, ни в IScenario, но должна быть исполнима scenarioObject'ом. если scenarioObject не способен выполнить эту команду, то Adapter или scenarioObject бросает исключение. полагаю, без магии и макросов в Адаптере тут не обойтись, но зато писать сценарии и сервисы будет наглядно. вот как такую хрень на c++/QT реализовать, или может кто ведел что похожее ? |
| Автор: Guinness 12.12.2013, 08:04 | ||||||||
Можно попробовать развить твою изначальную идею со списком команд. У сценария есть список команд, которые он может выполнить, и у сервиса есть список команд, которые ему необходимы для работы. В этом случае для каждого сервиса пишется свой "адаптер", который принимает на вход список команд сценария или сам сценарий. И уже потом предоставляет прозрачный интерфейс для сервиса как у тебя показано ниже.
Почему? Я думал про написание аналога QVariant. Но раз мы работаем с Qt, то всё нормально. Просто его и возьмем, т.е. получится как-то так:
Честно говоря, я не представляю, как это можно сделать в плюсах. Что-то подобное можно сделать на Python. Хотя, слушай, в Qt есть мета-объектная система. Если не ошибаюсь, то там можно динамически добавлять свойства к объекту, только вот не знаю поможет это или нет в данном вопросе. У сервиса в этом случае получается строго ограниченный интерфейс для вызова команд сценария. Как не крути, т.к. ты в коде заранее указываешь что и как ему вызывать. |
| Автор: CompWorm 12.12.2013, 20:20 | ||
Guinness, спасибо+, пойду пересплю с новой информацией. попозже отпишу.
забыл сказать, сервис конечно знает эту сигнатуру и может ее передать для анализа в адаптер. то есть нужно адаптеру сравнить сигнатуры он сервиса и сценария и сбиндит их.. аля сигнал слот как-то. |
| Автор: Guinness 13.12.2013, 22:28 |
Рад, что чем-то помог. Но тут, я думаю, ещё много напильником придётся допиливать до работоспособной схемы) |
| Автор: CompWorm 16.12.2013, 21:29 | ||||||||||||||||||||
| с магией QT получилось следующее: (это переписанный код на нашу терминологию, мог что-то лишнее стереть или добавить...) i_scenario.h
a_scenario_adapter.h (абстракция адаптера к сценарию. адаптер будет поставляться вместе с сервисом.)
serial_connector.h (может IsA HasA)
serial_connector.cpp
scenario_adapter.h (через этот адаптер сервис будет общаться с неизвестным сценарием)
scenario_adapter.cpp
some_scenario.h
some_scenario.cpp
some_service.h (ну и собственно, как оно используется)
some_service.cpp
итак, я написал свой вариант с блэкджеком и шлюхами. общая идея - подцепить поддерживаемые слоты сценария к сигналам адаптера, который поставляется с сервисом, ориентируясь на UUID. в результате шлюхи ("UUID~3") не востребованы, блэкджек ("UUID~1") запитан на unsupportedSlot() (откуда по желанию может бросить исключение), но счастье ("UUID~2") будет. работает, смотрится нативно, но... минус этого решения - emit doSomething() не возвращает ничего позже попробую на колбеках повторить, чтобы победить эту проблему. |
| Автор: Guinness 17.12.2013, 07:14 | ||
Можно попробовать boost::signals2 или хотя бы идею реализации колбеков взять оттуда. |
| Автор: CompWorm 17.12.2013, 21:29 | ||||
| нет, все совсем просто. забыл вчера отписаться some_scenario.h
scenario_adapter.cpp
ничего коннектить не надо. на чистом C++ без макросов или boost не получится, но делать надо тоже самое - вернуть массив пойнтеров на мемберы. всем спасибо, тема закрыта. |