Определить метод интерфейса, который принимает разные параметры
В моем приложении используются измерительные приборы, подключенные к ПК. Я хочу, чтобы можно было использовать аналогичные инструменты у разных поставщиков.
Итак, я определил интерфейс:
interface IMeasurementInterface
{
void Initialize();
void Close();
}
Пока все хорошо. Перед измерением мне нужно настроить прибор, и это означает, что для разных приборов очень разные параметры. Поэтому я хочу определить метод, который принимает параметры, которые могут иметь разные структуры:
interface IMeasurementInterface
{
void Initialize();
void Close();
void Setup(object Parameters);
}
Затем я передам объект во все, что мне нужно. Это путь?
Ответы
Ответ 1
Вам может быть лучше придумать абстрактный класс "Параметры", который расширяется каждым из разных параметров инструментов... например. а затем с помощью Generics, чтобы убедиться, что правильные параметры переданы правильным классам...
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
{
}
Ответ 2
Мне кажется, что Factory шаблон может быть полезен, особенно если вы собираетесь в unit test ваше приложение.
Ответ 3
Если вы собираетесь иметь дело с более чем одним типом устройства, то разделение интерфейса контроллера + устройства, которое обменивается данными с использованием пар "Имя 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, - это следить за передачей команд контроллеру. Контроллер должен следить за коммуникацией устройства.
Преимущества разделения интерфейса
Защитить снова изменения
Такая развязка позволит вам изолировать код приложения от контроллера. Изменения в устройстве не влияют на ваш код пользователя.
Поддержание работоспособности кода приложения
Добавление кода пользователя всегда чистое, и вам нужно беспокоиться только с логикой приложения. Но если бы вы определили несколько интерфейсов/созданных шаблонов или дженериков с несколькими типами структур параметров, характерных для контроллера, ваш код имел бы много зависящего от устройства мусора в нем, что могло бы повредить читаемость и создавать проблемы обслуживания при изменении вашего устройства/его параметров.
Простота выполнения
Вы также можете убрать разные реализации контроллера в свои собственные проекты. Кроме того, ваше приложение может также настраивать команды и ответы более динамично, используя файлы XML и т.д., Которые могут поставляться вместе с классами контроллеров, чтобы все ваше приложение стало более динамичным по своей природе.
Реальная жизнь
Один из последних проектов контроллера производства от лидера в этом домене работает одинаково. Но они используют LON для связи с устройством.
LON?
Протокол LON, используемый в контроллерах (думаю, кондиционер/котел/вентиляторы и т.д.), использует эту концепцию для общения с различными устройствами.
Итак, все, что вам нужно, это единый интерфейс, который может разговаривать с вашим устройством, а затем отправляет ему пару значений имени, используя LON. использование стандартного протокола также позволит вам разговаривать с другими устройствами, кроме вашего измерительного прибора. Существуют версии с открытым исходным кодом LON, если ваше устройство использует LON.
Если ваше устройство не поддерживает LON, вам может потребоваться создать что-то, где код пользователя все еще работает с парами значений имени, а противоположный интерфейс преобразует ваши пары значений имени в эквивалент, соответствующий структуре cotroller struct +, и связывается с индивидуальным устройством в что устройство понимает.
Надеюсь, это пригодится.
Ответ 4
Это зависит от того, как вы собираетесь получать параметры в первую очередь. Если они хранятся в таблице базы данных или в файле конфигурации где-то, и это просто значения, которые необходимо установить, тогда передача в словаре, вероятно, сделает это (хотя вы потеряете безопасность типа). Если ваши процессы настройки будут немного сложнее, я бы подумал о том, чтобы отвлечь процесс установки немного дальше и выполнить двойную отправку (нажатие операции трансляции в новый класс настройки). Как этот
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);
}
}
Таким образом, вы не испортили свою иерархию классов измерений (или не обеспечивали реализацию и считали, что все реализации будут делать то, что вы хотите). Это также означает, что вы можете протестировать свой код установки, перейдя в поддельное (или Mocked) устройство измерения.
Если процесс настройки должен обрабатывать частные или защищенные данные, вы можете сделать конкретную реализацию IConfigurer внутри своего соответствующего класса Measurement.
Ответ 5
Мне нужно это для моего программного обеспечения, поскольку мне нужно поддерживать множество различных типов контроллеров движения для металлорежущих станков.
В вашем интерфейсе есть необходимые вам основы. Необходимо помнить, что вам не нужно передавать список параметров. Вы указали, что каждый тип устройства может иметь совсем другой тип настройки.
То, как я это делаю, выглядит следующим образом
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.
Моя общая философия заключается в том, что треугольный диалог реализуется в той же сборке, при условии, что он является приватным для сборки и вызывается объектом, реализующим на стандартных интерфейсах, которые я настраиваю. Опять же, причина этого заключается в том, что я считаю, что скрытие внутренних компонентов более ценно, чем попытка реализовать все диалоги в сборке верхнего уровня.
Указывая метод чтения и метод Store, вы устраняете необходимость раскрывать параметры внутренней настройки для сохранения. Все, что вам нужно, это передать любой тип хранилища файлов, который вы используете, чтобы сохранить параметры настройки.
Наконец, как и другой плакат, вам нужно настроить класс Factory в вашей сборке, содержащий все ваши измерительные устройства. Во время установки вам необходимо создать экземпляр этого класса и получить список поддерживаемых измерительных устройств.
Как я это делаю, мой класс Factory получает список контроллеров движения. Этот список является частью мастер-класса, в котором хранятся все классы установки. Когда я читаю мои установочные файлы, я получаю используемые на самом деле контроллеры. Я извлекаю эти классы из списка и помещаю их в другой список, который фактически используется во время процесса резания.
Причина, по которой я делаю это, заключается в том, что когда пользователь настраивает контроллеры движения, он должен иметь возможность выбирать из списка ВСЕХ доступных элементов управления, чтобы сообщить программному обеспечению, которое у него есть. Я считаю, что он более отзывчив, чтобы сохранить список доступных контроллеров.
Ответ 6
Это, вероятно, сработает. Другой вариант - передать параметры в словаре.