Определить метод интерфейса, который принимает разные параметры

В моем приложении используются измерительные приборы, подключенные к ПК. Я хочу, чтобы можно было использовать аналогичные инструменты у разных поставщиков.

Итак, я определил интерфейс:

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

Это, вероятно, сработает. Другой вариант - передать параметры в словаре.