Отделение зависимостей от железа
Хочу посоветоваться с любопытным и видимо очень умным читателем данного форума.
Для меня поставили задачу. "Отделить все что касается железа и инакпсулировать все это в одном месте".
Сейчас вот сижу прикидываю как это можно реализовать. В голову к сожалению приходит только одна идея.
Создание "Фасада" (таковым его можно назвать с натяжкой, но все же планируемый класс по своей сути будет ближе всего именно к данному патерну), который представляет собой, собственно говоря, класс по управлению железом. Назовем его "HardWare".
Код этого класса должен компилироваться вместе с самой программой.
Производные классы относящиеся к устройствам: модемы, принтеры и т.д. выносим в отдельную dll-ку (сборку) - Devices.dll.
Далее наш синглтон Hardware будет отвечать за динамискую загрузку Devices.dll. После загрузки будет инициализировать свои внутрение поля - экземплярами синглтонами данных устройств. Нужно также отметить что интерфейсы устройтсв(или базовые классы возможно представляющие собой null-объекты) будут находиться в базовой программе вместе. Именно с этими интерфейсами и будет работать класс Hardware.
В результате мы получим гибкую систему, у которой можно в динамике подменять dll-ку (сборку) с устройствами,- перед запуском приложения, например.
Гм...может у кого нибудь есть более интересное проектное решение. Рад буду выслушать:)
Не тронь Будду:D
Однако, обычно, я работаю с одной железякой - потому она и так у меня описывается в одном классе, без всяких декораторов и прочих хитрых паттернов. Заменитель подключаю статически, как исполнимый файл. Остальная программа его видит через хедер, который также является хедером класса для реального железа. То есть, я тупо меняю исполнимые файлы.
С длл-кой динамичнее, но, думаю, больше риск перепутать режим симулятора с режимом реального железа.
Преимущества этого, что при смене протокола или производителя девайса меняется чаще всего только "низкоуровневый" класс.
Преимущества этого, что при смене протокола или производителя девайса меняется чаще всего только "низкоуровневый" класс.
Ну, у меня примерно так же. Я говорил только про "низкоуровневый класс". Однако, он у меня не находится в одной иерархии классов со вторым и третьим. Третий у меня почти чисто абстрактный класс, единственная реализованная функция которого - возврат экземпляра второго класса. Второй реализует абстрактные функции третьего, плюс имеет свои дополнительные функции и данные, о которых внешний мир ничего не знает. То есть полная инкапсуляция приватных функций и данных :)
Еще один плюс такого поддельного "низкоуровневого" класса - можно тестировать всякие хитрые режимы работы железа. Например, если у нас есть датчик температуры, который измеряет в диапазоне 200 градусов, то постоянно тестировать прогу, нагревая и остужая датчик в какой-нибудь камере, слишком затратно по времени.
Но это тонкости. Вообще, можно сделать и с длл. Это лучше, если у пользователя постоянно меняются железяки, например.
Преимущества этого, что при смене протокола или производителя девайса меняется чаще всего только "низкоуровневый" класс.
Да это MVC в чистом виде!:)
Грамотные программисты в больших проектах только так и работают:)))
А увеличение дальнейшего кол-ва уровней, обычно необходимо при разложении уровня M(model, он же уровень бизнес логики) на несколько уровней абстракции. Это очень грамотный на мой взгляд ход, потому что позволяет управлять сложностью восприятия программы.
Сразу видно грамотного и опытного программиста.
Однако, обычно, я работаю с одной железякой - потому она и так у меня описывается в одном классе, без всяких декораторов и прочих хитрых паттернов. Заменитель подключаю статически, как исполнимый файл. Остальная программа его видит через хедер, который также является хедером класса для реального железа. То есть, я тупо меняю исполнимые файлы.
С длл-кой динамичнее, но, думаю, больше риск перепутать режим симулятора с режимом реального железа.
Я практически так и сделал!:)
Воистину мысли умных людей как правило схожи...
На самом деле то были первые мысли, так сказать, то что в голову сразу пришло...Сейчас уже схема нарисованная лежит на столе...
Выше я говорил о гибриде абстрактной фабрики и на фасада.
Нужен этот своебразный "шлюз" для устройств, потому что этих самых устройств много...порядка десяти...
(будь у меня одно устройство, я бы также как ты сделал:)
+необходимо обеспечить модульность...
+там будет пара общих операции операции,работающих одновременно со всеми устроиствами, - что-то типа InitilizeAllDevices, ParseDeviceConfig - считывание настроек конфига...и настройка всех устройств...
+ну и наконец вклассе Hardware будут методы возвращающие синглтоны соответсвующие конкретному устройству, абстрагируясь от модели устройства...
Ввиду того что устройств много пришло еще ввести и наследование...утяжелил эту схему 3-х уровневым наследованием
1)Базовое устройство(любое устройство)
2)Типовое устройство(базовый принтер, базовый модем, и т.д.) 3)Конкретная модель...
Хедеры, увы передать в использующих код не получится, потому что эти dll-ки написанные на плюсах, будет юзать проект написанный на C#:)
Придется там интерфейс прописывать...в рамках всего проекта
Ну а насчет подмены исполняемых файлов, думаю стоит каждое устройство вынести в отдельную библиотеку, и тогда в рантайме...поменили у терминала модем....мы хренак на терминал новую длл-ку modem.dll...и вуаля...все нормально работает:)
И не требует даже выключения терминала...
Я вот только не знаю где правильней шлюз "Hardware" реализовывать в C# или в плюсах...наверное все-таки со стороны основной программы...
Спасибо. :)
Выше я говорил о гибриде абстрактной фабрики и на фасада.
+там будет пара общих операции операции,работающих одновременно со всеми устроиствами, - что-то типа InitilizeAllDevices, ParseDeviceConfig - считывание настроек конфига...и настройка всех устройств...
+ну и наконец вклассе Hardware будут методы возвращающие синглтоны соответсвующие конкретному устройству, абстрагируясь от модели устройства...
У тебя будет пара (всего пара!) общих операций. Значит, будут и не общие?
Hardware будет возвращать интерфейсы экземпляров (синглтоны)?
Тогда это не фасад. Фасад не раскрывает внутреннего содержимого, т.к. его цель как раз обратная.
Это менеджер. Он отвечает (в общем случае) за создание, уничтожение, управление и шаринг контролируемых объектов.
Кстати, ты уверен, что тебе необходимы синглтоны?
Я не рекомендую завязывать архитектуру на синглтоны. Можешь поискать по форуму, про то, как они мне встали, как кость в горле.
Раньше тоже считали, что в квартире достаточно одной ванной комнаты... :)
Если уж нужно контролировать уникальность объекта, пусть это делает все тот же менеджер.
Хедеры, увы передать в использующих код не получится, потому что эти dll-ки написанные на плюсах, будет юзать проект написанный на C#:)
Придется там интерфейс прописывать...в рамках всего проекта
А такое смешение необходимо?
Ну а насчет подмены исполняемых файлов, думаю стоит каждое устройство вынести в отдельную библиотеку, и тогда в рантайме...поменили у терминала модем....мы хренак на терминал новую длл-ку modem.dll...и вуаля...все нормально работает:)
И не требует даже выключения терминала...
Ты уже продумал реализацию синглтонов с учетом разных DLL ?
А продумал, какие накладные расходы и сложности это привнесет?
Ну и нафига? Не проще ли поручить это дело менеджеру и заодно решить "проблему 2000", т.е. продумать будущее развитие системы. Например, потребуется, чтоб был не строго один модем, а СТРОГО два (не больше, не меньше). С синглтонами тебе придется перефигачивать кучу кода (относящуюся ко всем видам модемов). А с менджером,- лишь подправить его код.
Hardware будет возвращать интерфейсы экземпляров (синглтоны)?
Пока пара, в будущем возможно больше...пара это только первые прикидки...
В классе Hardware наряду с общими методами будут методы...
IModem* GetModem()
IPrinter* GetPrinter()
.....
И т.д.
Возможно метод InitializeAllDevices() вообще не нужен...все будут выполнять методы запроса интерфейсов устройств, если, например, устройство запрашивается в первый раз...
По своему внешнему виду класс Hardware похож на абстрактную фабрику, только все-таки он создает устройство только при первом обращении, а не каждый раз...так что пожалуй абстрактной фабрикой этот класс не является...
Классы устройств действительно не должны быть синглтонами - лишний ненужный геморой - здесь полностью согласен с тобой:)...
Cинглтоном будет класс Hardware...(заметь ведь абстрактные фабрики очень часто тоже являются Синглтонами...это еще одно сходство с этим патерном:)
А вот здесь ты не прав. Фасад ни коим образом ни припятствует обращению к системе подклассов которая скрывается за ним, напрямую.
Он лишь в дополнение предоставляя какие-то общие операции. Цель его использования - увеличение модульности приложения.
В нашем случае класс Hardware с этими обязаностями справляется.
См. книгу "Патерны проэктирования" Gang of Fourth.
Ты абсолютно прав!:)
Ты уже продумал реализацию синглтонов с учетом разных DLL ?
А продумал, какие накладные расходы и сложности это привнесет?
Ну насчет синглтонов по-моему мы к взаимопониманию пришли:)
Хочется отдельно поговорить о библиотеках...
На первый взгляд сложностей с подменой библиотек устройств возникнуть не должно...перед тем как её подменить надо будет сначала выгрузить старую библиотеку из адресного пространства процесса.
Загружаться библиотеки устройств также будут в динамике...и за это всё будет ответственным как раз класс Hardware.
Хочется отметить универсальность этого метода....за счет того что сам разработчик подсовывает необходимую и единственную dll-ку. Отпадает необходимость добавления и сопровождения условных ветвлений по выбору конкретных моделей принтеров, модемов и т.д. в классе Hardware
Написанных строк кода становится меньше и коэффициент сложности уменьшается:)