Определите метод интерфейса, который принимает различные параметры - PullRequest
11 голосов
/ 26 октября 2008

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

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

interface IMeasurementInterface
    {
        void Initialize();
        void Close();
    }

Пока все хорошо. Перед измерением мне нужно настроить прибор, а это значит, для разных приборов очень разные параметры. Поэтому я хочу определить метод, который принимает параметры, которые могут иметь различные структуры:

interface IMeasurementInterface
{
    void Initialize();
    void Close();
    void Setup(object Parameters);
}

Затем я приведу объект ко всему, что мне нужно. Это путь?

Ответы [ 6 ]

13 голосов
/ 26 октября 2008

Возможно, вам лучше придумать абстрактный класс «Параметры», который расширяется параметрами каждого отдельного инструмента ... например, а затем с помощью 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 голосов
/ 26 октября 2008

Мне кажется, что шаблон Factory может быть полезен, особенно если вы собираетесь тестировать приложение.

1 голос
/ 27 октября 2008

Мне нужно это для моего программного обеспечения, так как мне нужно поддерживать различные типы контроллеров движения для металлорежущих станков.

Ваш интерфейс имеет основы, которые вам нужны. Вам нужно помнить, что вам не нужно передавать список параметров. Вы указали, что у каждого типа устройства могут быть разные настройки.

Я делаю это следующим образом

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.

Моя общая философия заключается в том, что триальные диалоги реализуются в одной сборке при условии, что они являются частными для сборки и вызываются объектом, реализующим стандартные интерфейсы, которые я настраиваю. Опять же, причина этого в том, что я считаю, что скрывать внутренние компоненты более ценно, чем пытаться реализовать все диалоги в сборке верхнего уровня.

Указывая метод чтения и метод хранения, вы избавляете от необходимости выставлять внутренние параметры настройки для сохранения. Все, что вам нужно, это передать любой тип объекта хранения файлов, который вы используете для сохранения параметров настройки.

Наконец, как и в другом плакате, вам необходимо настроить заводской класс в сборке, содержащей все ваши измерительные устройства. Во время настройки вам нужно создать экземпляр этого класса и получить список поддерживаемых измерительных устройств.

То, как я это делаю, это мой фабричный класс, который получает список контроллеров движения. Этот список является частью мастер-класса, где хранятся все классы настройки. Когда я читаю мои установочные файлы, я получаю контроллеры, которые фактически используются. Я извлекаю эти классы из списка и помещаю их в другой список, который фактически используется в процессе вырезания.

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

1 голос
/ 27 октября 2008

Это зависит от того, как вы собираетесь получить параметры в первую очередь. Если они хранятся в таблице базы данных или в файле конфигурации где-то, и это просто значения, которые необходимо установить, то передача в словарь, вероятно, сделает это (хотя вы теряете безопасность типов). Если ваши процессы установки будут немного сложнее, я бы подумал об абстрагировании процесса установки немного дальше и выполнении двойной диспетчеризации (перевод операции приведения в новый класс установки). Как это

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);
  }
}

Таким образом, вы не портите иерархию классов Measurement (или не предоставляете реализацию и не предполагаете, что все реализации будут делать то, что вы хотите в любом случае). Это также означает, что вы можете проверить свой установочный код, передав поддельное (или поддельное) измерительное устройство.

Если процессу установки необходимо манипулировать частными или защищенными данными, тогда вы можете сделать так, чтобы конкретная реализация IConfigurer находилась внутри его соответствующего класса измерений.

1 голос
/ 27 октября 2008

Если вы собираетесь работать даже с несколькими типами устройств, то хорошим решением будет разделение интерфейса контроллер + устройство, которое обменивается данными с помощью пары имен 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 + и связывается с устройством индивидуума в способ, которым устройство понимает.

Надеюсь, это пригодится.

0 голосов
/ 26 октября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...