Мое приложение использует измерительные инструменты, которые подключены к ПК. Я хочу позволить использовать подобные инструменты от различных поставщиков.
Таким образом, я определил интерфейс:
interface IMeasurementInterface
{
void Initialize();
void Close();
}
Пока неплохо. Перед измерением я должен установить инструмент, и это означает для различных инструментов совсем другие параметры. Таким образом, я хочу определить метод, который берет параметры, которые могут иметь различные структуры:
interface IMeasurementInterface
{
void Initialize();
void Close();
void Setup(object Parameters);
}
Я тогда брошу объект к тому, в чем я нуждаюсь. Действительно ли это - способ пойти?
Вы могли бы быть более обеспечены придумывающий краткий обзор класс "Параметров", который расширяется каждым различные инструментальные параметры..., например, и затем использование Дженериков, чтобы гарантировать, что корректные параметры передаются корректным классам...
public interface IMeasurement<PARAMTYPE> where PARAMTYPE : Parameters
{
void Init();
void Close();
void Setup(PARAMTYPE p);
}
public abstract class Parameters
{
}
И затем для каждого определенного Устройства,
public class DeviceOne : IMeasurement<ParametersForDeviceOne>
{
public void Init() { }
public void Close() { }
public void Setup(ParametersForDeviceOne p) { }
}
public class ParametersForDeviceOne : Parameters
{
}
Мне это кажется, что Шаблон "фабрика" мог бы быть полезным, особенно если Ваш идут в модульный тест Ваше приложение.
Это зависит от того, как Вы собираетесь получить параметры во-первых. Если они будут сохранены прочь в таблице базы данных или файле конфигурации где-нибудь, и это - просто значения, которые должны быть установлены, затем передав в словаре, то вероятно, сделает это (хотя Вы действительно теряете безопасность типов). Если бы Ваши процессы установки будут немного более сложными затем, я считал бы абстракцию далеко процессом установки немного далее и выполнением двойной отправки (продвигающий операцию броска в новый класс установки). Как это
public interface IMeasurementInterface
{
void Initialize();
void Close();
void Setup( IConfigurer config );
}
public interface IConfigurer
{
void ApplyTo( object obj );
}
public abstract ConfigurerBase<T> : IConfigurer where T : IMeasurementInterface
{
protected abstract void ApplyTo( T item );
void IConfigurator.ApplyTo(object obj )
{
var item = obj as T;
if( item == null )
throw new InvalidOperationException("Configurer can't be applied to this type");
ApplyTo(item);
}
}
Таким образом, Вы не портите свою Измерительную иерархию классов (или не обеспечиваете реализации и предполагаете, что все реализации сделают то, что Вы хотите так или иначе). Это также означает, что можно протестировать код Установки путем передачи в фальшивке (или Дразнивший) Устройства измерения.
Если процесс установки должен управлять частными или защищенными данными затем, можно заставить конкретную реализацию IConfigurer находиться в его соответствующем Измерительном классе.
Это, вероятно, работало бы. Другая опция состоит в том, чтобы передать параметры в словаре.
Если Вы собираетесь иметь дело даже больше чем с одним типом устройства, то контроллер + разделение интерфейса устройства, которое передает Имя использования vlaue пары, был бы хорошим решением
ОТДЕЛЕНИЕ
Используя пары значение-имя позволяет Вам разделять свой код в устройство + контроллер + структура кода приложения
Пример кода
class DeviceInterface
{
void Initialize(IController & Controller);
void Close();
bool ChangeParameter(const string & Name, const string & Value);
bool GetParam(string & Name, string &Value );
}
Каждая реализация устройства при создании должна быть создана с идентификацией контроллера, который может принять его команды и перевести их в команды существующего устройства
interface IController
{
Initialize(DeviceSpecific & Params);
Close();
bool ChangeParameter(string & Name, string & Value);
bool ChangeParams(string & Name[], string &Value []);
}
Ваш пользовательский код выглядел бы примерно так
IController objController = new MeasurementDevice(MeasureParram);
DeviceInterface MeasureDevice = new DeviceInterface(objController);
string Value;
MeasureDevice.GetParam("Temperature", Value);
if (ConvertStringToInt(Value) > 80)
{
MeasureDevice.ChangeParameter("Shutdown", "True");
RaiseAlert();
}
Все, что должен сделать класс DeviceInterface, заботятся о передаче команд к контроллеру. Контроллер должен заботиться о коммуникации устройства.
Преимущества интерфейсного разделения
Защитите от изменений
Этот вид отделения позволит Вам изолировать свой код приложения от контроллера. Изменения в устройстве не влияют на Ваш пользовательский код
Пригодность для обслуживания кода Appliction
Addtionally пользовательский код является всегда чистым и Вы должны обеспокоиться только прикладной логикой. Но имел Вас, определил несколько интерфейсов / созданные шаблоны или дженерики с несколькими типами структур параметра, характерных для контроллера, Ваш код будет иметь много зависимого от устройств спама в нем, который мог бы повредить удобочитаемость и создать проблемы обслуживания каждый раз, когда Ваше устройство / его параметры изменяется.
Простота реализации
Можно также отделиться от различных реализаций контроллера в его собственные проекты. Плюс Ваше приложение может также настроить команды и ответы в более динамическом naure, использующем XML-файлы и т.д., которые могут поставляться наряду с классами контроллера, таким образом, что Ваше целое приложение становится более динамичным по своей природе.
Реальная жизнь
Один из последних производственных проектов контроллера от лидера в том домене работает таким же образом. Но они используют LON для коммуникации устройства.
LON?
Протокол LON, используемый в контроллерах (думают кондиционер / бойлер / вентиляторы и т.д.) сети, использует это понятие, чтобы говорить с различными устройствами
Таким образом, все, что Вы должны были бы иметь, является единственным интерфейсом, который может говорить с Вашим устройством и затем отправляет пару значение-имя в него с помощью LON., который он использует стандартного протокола, также позволит Вам говорить с другими устройствами помимо своего измерительного инструмента. Существуют реализации с открытым исходным кодом LON, доступного, если Ваше устройство использует LON.
Если Ваше устройство не поддерживает LON затем, Вам, возможно, придется разработать что-то, где пользовательский код все еще работает над парами значение-имя, и противоположный интерфейс переводит Ваши пары значение-имя в equivalet соответствующую cotroller структуру + и связывается с устройством индивидуумов в способе, которым понимает устройство.
Надежда это прибывает полезное.
Я имею к этому для моего программного обеспечения, поскольку я должен поддерживать много различных типов контроллеров перемещений для машин резки металла.
Ваш интерфейс имеет основы, в которых Вы нуждаетесь. Вещь, которую необходимо помнить, состоит в том, что Вы не должны передавать в списке параметров. Вы указали, что каждый тип устройства мог иметь совсем другой тип установки.
Путем я делаю это следующие
interface IMeasurementInterface
{
void Initialize();
void Close();
void Setup();
void Read (FileReader as <whatever read file object you are using>)
void Store (FileReader as <whatever read file object you are using>)
string Name();
}
Установка называет диалоговое окно созданным в блоке IMeasurementDevice. Диалоговое окно не Видимо за пределами блока.
Теперь я знаю, что некоторый объектно-ориентированный или пурист MVC может возразить против этого. Однако я чувствую, что понятие сокрытия внутренностей определенного Измерительного класса перевешивает строгое соблюдение архитектуры MVC.
Моя общая философия - то, что trival диалоговое окно реализовано в том же блоке при условии, что это является частным к блоку и названное реализацией объекта в стандартных интерфейсах, которые я устанавливаю. Снова причина этого, я нахожу, что сокрытие внутренностей более ценно, чем попытка реализовать все диалоговые окна в высокоуровневом блоке.
Путем определения Метода Чтения и метода Хранилища Вы избавляете от необходимости выставлять внутренние параметры установки для сохранения. Все, в чем Вы нуждаетесь, должно передать любой тип объекта хранилища файлов, который что Вы используете для сохранения параметров установки.
Наконец как другой плакат указал, что необходимо установить Класс Фабрики в блоке, содержащем все устройства измерения. Во время Вашей установки необходимо инстанцировать этого класса и получить список поддерживаемых устройств измерения.
Путем я делаю это - мой класс фабрики, получает список контроллеров перемещений. Этот список является частью мастер-класса, где все классы установки хранятся. Когда я считал свои файлы настройки, я получаю контроллеры, которые на самом деле используются. Я получаю те классы из списка и размещаю их в другой список, который на самом деле используется во время сокращающего процесса.
Причина я делаю это этот путь, состоит в том, что, когда пользователь настраивает контроллеры перемещений, он должен смочь выбрать из списка ВСЕХ доступных элементов управления для сообщения программного обеспечения, какой он имеет. Я нахожу это более быстро реагирующим для имения в наличии списка доступных контроллеров.