que - no se puede crear una instancia de la clase o interfaz abstracta c#
Definir un método de interfaz que tome diferentes parámetros (6)
Eso probablemente funcionaría. Otra opción es pasar los parámetros en un diccionario.
Mi aplicación utiliza instrumentos de medición que están conectados a la PC. Quiero hacer posible el uso de instrumentos similares de diferentes proveedores.
Así que definí una interfaz:
interface IMeasurementInterface
{
void Initialize();
void Close();
}
Hasta aquí todo bien. Antes de una medición necesito configurar el instrumento y esto significa para diferentes instrumentos parámetros muy diferentes. Entonces quiero definir un método que tome parámetros que pueden tener diferentes estructuras:
interface IMeasurementInterface
{
void Initialize();
void Close();
void Setup(object Parameters);
}
Luego lanzaré el objeto a lo que sea que necesite. ¿Es este el camino a seguir?
Para mí, suena como el patrón de fábrica podría ser útil, especialmente si vas a probar tu aplicación unitariamente.
Puede que sea mejor crear una clase abstracta de "Parámetros" que se amplíe con los parámetros de cada instrumento ... por ejemplo, y luego usar Generics para garantizar que los parámetros correctos se pasen a las clases correctas ...
public interface IMeasurement<PARAMTYPE> where PARAMTYPE : Parameters
{
void Init();
void Close();
void Setup(PARAMTYPE p);
}
public abstract class Parameters
{
}
Y luego para cada dispositivo específico,
public class DeviceOne : IMeasurement<ParametersForDeviceOne>
{
public void Init() { }
public void Close() { }
public void Setup(ParametersForDeviceOne p) { }
}
public class ParametersForDeviceOne : Parameters
{
}
Depende de cómo va a obtener los parámetros en primer lugar. Si están almacenados en una tabla de base de datos o un archivo de configuración en algún lugar y solo son valores que deben establecerse, pasarlo en un diccionario probablemente lo haga (aunque se pierde seguridad de tipo). Si sus procesos de configuración van a ser un poco más complicados, consideraría abstraer el proceso de configuración un poco más y realizar un despacho doble (empujando la operación de conversión a una nueva clase de configuración). Me gusta esto
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);
}
}
De esta forma, no está arruinando su jerarquía de clases de Medición (o proporcionando ninguna implementación y suponiendo que todas las implementaciones harán lo que usted desea de todos modos). También significa que puede probar su código de instalación pasando un dispositivo de medición falso (o burlado).
Si el proceso de instalación necesita manipular datos privados o protegidos, puede hacer que la implementación concreta del IConfigurer resida dentro de su clase de medición correspondiente.
Si va a tratar incluso con más de un tipo de dispositivo, entonces la separación entre la interfaz del controlador y el dispositivo, que se comunica utilizando los pares Name vlaue, sería una buena solución.
DESACOPLAMIENTO
El uso de pares de valores de nombre le permite separar su código en una estructura de código de dispositivo + controlador + aplicación
Código de muestra
class DeviceInterface
{
void Initialize(IController & Controller);
void Close();
bool ChangeParameter(const string & Name, const string & Value);
bool GetParam(string & Name, string &Value );
}
La implementación de cada dispositivo, cuando se cree, debe crearse con la identificación del controlador que puede aceptar sus comandos y traducirlos a los comandos reales del dispositivo.
interface IController
{
Initialize(DeviceSpecific & Params);
Close();
bool ChangeParameter(string & Name, string & Value);
bool ChangeParams(string & Name[], string &Value []);
}
Su código de usuario sería algo como esto
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();
}
Todo lo que debe hacer la clase DeviceInterface es pasar los comandos al controlador. El controlador debe encargarse de la comunicación del dispositivo.
Ventajas de la separación de interfaz
Proteger los cambios en el sitio
Este tipo de desacoplamiento le permitirá aislar el código de su aplicación del controlador. Los cambios en el dispositivo no afectan su código de usuario
Mantenimiento del código de aplicación
Además, el código de usuario siempre está limpio y solo debe preocuparse por la lógica de la aplicación. Pero si hubiera definido múltiples interfaces / plantillas creadas o genéricos con múltiples tipos de estructuras de parámetros específicas para el controlador, su código tendría una gran cantidad de basura dependiente del dispositivo que podría dañar la legibilidad y crear problemas de mantenimiento cada vez que su dispositivo / sus parámetros cambien.
Facilidad de implementación
También puede organizar diferentes implementaciones de controlador en sus propios proyectos. Además, su aplicación también puede configurar comandos y respuestas de una forma más dinámica usando archivos XML, etc. que pueden enviarse junto con las clases de controlador, de modo que toda su aplicación se vuelva más dinámica por naturaleza.
Vida real
Uno de los últimos proyectos de controlador de producción del líder en ese dominio funciona de la misma manera. Pero usan LON para la comunicación del dispositivo.
LON?
El protocolo LON utilizado en las redes de controladores (piensa en el aire acondicionado / caldera / ventiladores, etc.) usa este concepto para hablar con varios dispositivos
Entonces, todo lo que necesitaría tener es una única interfaz que pueda comunicarse con su dispositivo y luego le envíe el par de valores nominales usando LON. El uso de un protocolo estándar también le permitirá hablar con otros dispositivos además de su instrumento de medición. Existen implementaciones de código abierto de LON disponibles si su dispositivo usa LON.
Si su dispositivo no es compatible con LON, es posible que tenga que diseñar algo donde el código de usuario funcione en pares de valores nominales y una interfaz opuesta traduzca sus pares de valores nominales en una estructura de cotroller correspondiente equivalente y se comunique al dispositivo individual de la forma en que el dispositivo entiende
Espero que esto sea útil.
Tengo que hacer esto para mi software ya que necesito admitir muchos tipos diferentes de controladores de movimiento para máquinas de corte de metales.
Su interfaz tiene los elementos básicos que necesita. Lo que debe recordar es que no necesita pasar una lista de parámetros. Usted señaló que cada tipo de dispositivo podría tener un tipo de configuración muy diferente.
La forma en que lo hago es la siguiente
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();
}
El programa de instalación llama a un cuadro de diálogo creado en el conjunto del dispositivo IMeasurement. El cuadro de diálogo NO es visible fuera del ensamblaje.
Ahora sé que algunos orientados a objetos o puristas MVC pueden oponerse a esto. Sin embargo, creo que el concepto de ocultar las partes internas de una clase de medición específica supera la adhesión estricta a la arquitectura MVC.
Mi filosofía general es que el diálogo de trival se implementa en el mismo ensamblado siempre que sea privado para el ensamblado y lo invoque un objeto que implemente en las interfaces estándar que configuro. Una vez más, la razón de esto es que encuentro que ocultar las partes internas es más valioso que tratar de implementar todos los cuadros de diálogo en el ensamblaje de nivel superior.
Al especificar un Método de lectura y un método de Tienda, elimina la necesidad de exponer los parámetros de configuración internos para guardar. Todo lo que necesita es pasar cualquier tipo de objeto de almacenamiento de archivos que esté utilizando para guardar sus parámetros de configuración.
Finalmente, al igual que otro cartel, indicó que necesita configurar una clase de fábrica en su ensamblaje que contenga todos sus dispositivos de medición. Durante la configuración, debe crear una instancia de esta clase y recuperar la lista de dispositivos de medición admitidos.
La forma en que lo hago es que mi clase de fábrica recupera una lista de controladores de movimiento. Esta lista es parte de una clase maestra donde se almacenan todas las clases de configuración. Cuando leo mis archivos de configuración, obtengo los controladores que realmente están siendo utilizados. Recupero esas clases de la lista y las coloco en otra lista que realmente se usa durante el proceso de corte.
La razón por la que lo hago de esta manera es que cuando el usuario está configurando controladores de movimiento, debe poder elegir de una lista de TODOS los controles disponibles para decirle al software cuál tiene. Encuentro más receptivo mantener una lista de controladores disponibles.