Antecedentes
Tengo un proyecto que depende del uso de cierto tipo de dispositivo de hardware, mientras que en realidad no importa quién haga ese dispositivo de hardware siempre que haga lo que necesito que haga. Dicho esto, incluso dos dispositivos que se supone que deben hacer lo mismo tendrán diferencias cuando no sean fabricados por el mismo fabricante. Por lo tanto, estoy pensando en usar una interfaz para desacoplar la aplicación de la marca / modelo particular del dispositivo involucrado y, en cambio, hacer que la interfaz cubra la funcionalidad de más alto nivel. Así es como creo que se verá mi arquitectura:
- Defina una interfaz en un proyecto de C #
IDevice
. - Tenga un concreto en una biblioteca definida en otro proyecto de C #, que se usará para representar el dispositivo.
- Haga que el dispositivo concreto implemente la
IDevice
interfaz. - La
IDevice
interfaz puede tener métodos comoGetMeasurement
oSetRange
. - Haga que la aplicación tenga conocimiento sobre el concreto y pase el concreto al código de la aplicación que utiliza ( no implementa ) el
IDevice
dispositivo.
Estoy bastante seguro de que esta es la forma correcta de hacerlo, porque así podré cambiar qué dispositivo se está utilizando sin afectar la aplicación (lo que parece suceder a veces). En otras palabras, no importará cómo las implementaciones GetMeasurement
o SetRange
realmente funcionan a través del concreto (ya que pueden diferir entre los fabricantes del dispositivo).
La única duda en mi mente es que ahora tanto la aplicación como la clase concreta del dispositivo dependen de la biblioteca que contiene la IDevice
interfaz. Pero, ¿es eso algo malo?
Tampoco veo cómo la aplicación no necesitará saber sobre el dispositivo, a menos que el dispositivo IDevice
esté en el mismo espacio de nombres.
Pregunta
¿Parece este el enfoque correcto para implementar una interfaz para desacoplar la dependencia entre mi aplicación y el dispositivo que utiliza?
Respuestas:
Creo que tienes una buena comprensión de cómo funciona el software desacoplado :)
¡No necesita ser!
Puede abordar todas estas inquietudes con la Estructura del proyecto .
La forma en que normalmente lo hago:
Common
proyecto. Algo así comoMyBiz.Project.Common
. Otros proyectos son libres de referenciarlo, pero es posible que no haga referencia a otros proyectos.MyBiz.Project.Devices.TemperatureSensors
. Este proyecto hará referencia alCommon
proyecto.Client
proyecto, que es el punto de entrada a mi aplicación (algo así comoMyBiz.Project.Desktop
). Al inicio, la aplicación pasa por un proceso de Bootstrapping donde configuro asignaciones de abstracción / implementación concreta. Puedo crear instancias de mi concretoIDevices
comoWaterTemperatureSensor
yIRCameraTemperatureSensor
aquí, o puedo configurar servicios como Fábricas o un contenedor IoC para instanciar los tipos de concreto adecuados para mí más adelante.La clave aquí es que solo su
Client
proyecto necesita conocer tanto elCommon
proyecto abstracto como todos los proyectos de implementación concretos. Al limitar el mapeo abstracto-> concreto a su código Bootstrap, está haciendo posible que el resto de su aplicación desconozca completamente los tipos concretos.Código vagamente acoplado ftw :)
fuente
new Foo(new DeviceA());
), en lugar de tener un campo privado dentro de Foo instanciar el Dispositivo A (private IDevice idevice = new DeviceA();
) - todavía logra DI, como Foo no tiene conocimiento de DeviceA en el primer casoSí, ese parece ser el enfoque correcto. No, no es malo que la aplicación y la biblioteca de dispositivos dependan de la interfaz, especialmente si usted tiene el control de la implementación.
Si le preocupa que los dispositivos no siempre implementen la interfaz, por cualquier razón, puede utilizar el patrón del adaptador y adaptar la implementación concreta de los dispositivos a la interfaz.
EDITAR
Al abordar su quinta preocupación, piense en una estructura como esta (supongo que tiene el control de definir sus dispositivos):
Tienes una biblioteca central. En ella hay una interfaz llamada IDevice.
En su biblioteca de dispositivos, tiene una referencia a su biblioteca principal, y ha definido una serie de dispositivos que implementan IDevice. También tiene una fábrica que sabe cómo crear diferentes tipos de IDevices.
En su aplicación, usted incluye referencias a la biblioteca central y la biblioteca de dispositivos. Su aplicación ahora usa la fábrica para crear instancias de objetos que se ajustan a la interfaz IDevice.
Esta es una de las muchas formas posibles de abordar sus inquietudes.
EJEMPLOS
fuente
Tienes que pensar al revés. Si no va por este camino, la aplicación necesitaría conocer todos los diferentes dispositivos / implementaciones. Lo que debe tener en cuenta es que cambiar esa interfaz podría romper su aplicación si ya está en estado salvaje, por lo tanto, debe diseñar esa interfaz con cuidado.
Simplemente si
La aplicación puede cargar el conjunto de hormigón (dll) en tiempo de ejecución. Ver: /programming/465488/can-i-load-a-net-assembly-at-runtime-and-instantiate-a-type-knowing-only-the-na
Si necesita descargar / cargar dinámicamente dicho "controlador", debe cargar el ensamblado en un dominio de aplicación separado .
fuente
IDevice
interfaz para que su dispositivo pueda usarse con su aplicación, entonces no habría otra forma de IMO.