Contexte
J'ai un projet qui dépend de l'utilisation d'un certain type de périphérique matériel, alors peu importe qui fabrique ce périphérique tant qu'il fait ce dont j'ai besoin. Cela étant dit, même deux appareils qui sont censés faire la même chose auront des différences lorsqu'ils ne sont pas fabriqués par le même fabricant. Je pense donc à utiliser une interface pour dissocier l'application de la marque / du modèle particulier du périphérique concerné, et à la place, l'interface ne couvre que les fonctionnalités de plus haut niveau. Voici à quoi je pense que mon architecture ressemblera:
- Définissez une interface dans un projet C #
IDevice
. - Avoir un concret dans une bibliothèque définie dans un autre projet C #, qui sera utilisé pour représenter le périphérique.
- Demandez au dispositif concret de mettre en œuvre l'
IDevice
interface. - L'
IDevice
interface peut avoir des méthodes commeGetMeasurement
ouSetRange
. - Faites en sorte que l'application connaisse le béton et passez le béton au code d'application qui utilise (et non implémente ) le
IDevice
périphérique.
Je suis à peu près sûr que c'est la bonne façon de procéder, car je pourrai alors changer le périphérique utilisé sans affecter l'application (ce qui semble parfois se produire). En d'autres termes, peu importe la façon dont les implémentations GetMeasurement
ou SetRange
fonctionnent réellement à travers le béton (comme cela peut différer selon les fabricants de l'appareil).
Le seul doute dans mon esprit, c'est que maintenant l'application et la classe concrète du périphérique dépendent toutes deux de la bibliothèque qui contient l' IDevice
interface. Mais est-ce une mauvaise chose?
Je ne vois pas non plus comment l'application n'aura pas besoin de connaître le périphérique, sauf si le périphérique et se IDevice
trouvent dans le même espace de noms.
Question
Cela semble-t-il être la bonne approche pour implémenter une interface pour découpler la dépendance entre mon application et le périphérique qu'elle utilise?
Réponses:
Je pense que vous avez une assez bonne compréhension du fonctionnement des logiciels découplés :)
Ce n'est pas nécessaire!
Vous pouvez traiter toutes ces préoccupations avec la structure du projet .
La façon dont je le fais généralement:
Common
projet. Quelque chose commeMyBiz.Project.Common
. D'autres projets sont libres de le référencer, mais il peut ne pas faire référence à d'autres projets.MyBiz.Project.Devices.TemperatureSensors
. Ce projet fera référence auCommon
projet.Client
projet qui est le point d'entrée de mon application (quelque chose commeMyBiz.Project.Desktop
). Au démarrage, l'application passe par un processus d' amorçage où je configure les mappages d'abstraction / mise en œuvre concrète. Je peux instancier mon bétonIDevices
commeWaterTemperatureSensor
etIRCameraTemperatureSensor
ici, ou je peux configurer des services comme des usines ou un conteneur IoC pour instancier les bons types de béton pour moi plus tard.L'essentiel ici est que seul votre
Client
projet doit être conscient à la fois duCommon
projet abstrait et de tous les projets concrets de mise en œuvre. En confinant le mappage abstrait-> concret à votre code Bootstrap, vous permettez au reste de votre application d'ignorer parfaitement les types concrets.Code ftw faiblement couplé :)
la source
new Foo(new DeviceA());
), plutôt que d'avoir un champ privé dans Foo instancier DeviceA lui-même (private IDevice idevice = new DeviceA();
) - vous obtenez toujours DI, comme Foo n'est pas au courant de DeviceA dans le premier casOui, cela semble être la bonne approche. Non, ce n'est pas une mauvaise chose pour l'application et la bibliothèque de périphériques de dépendre de l'interface, surtout si vous contrôlez l'implémentation.
Si vous craignez que les périphériques n'implémentent pas toujours l'interface, pour une raison quelconque, vous pouvez utiliser le modèle d'adaptateur et adapter l'implémentation concrète des périphériques à l'interface.
ÉDITER
En répondant à votre cinquième préoccupation, pensez à une structure comme celle-ci (je suppose que vous contrôlez la définition de vos appareils):
Vous avez une bibliothèque principale. Il contient une interface appelée IDevice.
Dans votre bibliothèque de périphériques, vous avez une référence à votre bibliothèque principale et vous avez défini une série de périphériques qui implémentent tous IDevice. Vous disposez également d'une usine qui sait créer différents types d'IDevices.
Dans votre application, vous incluez des références à la bibliothèque principale et à la bibliothèque de périphériques. Votre application utilise désormais la fabrique pour créer des instances d'objets conformes à l'interface IDevice.
C'est l'une des nombreuses façons possibles de répondre à vos préoccupations.
EXEMPLES:
la source
Vous devez penser l'inverse. Si vous ne procédez pas de cette façon, l'application devra connaître tous les différents appareils / implémentations. Ce que vous devez garder à l'esprit, c'est que changer cette interface pourrait casser votre application si elle est déjà dans la nature, donc vous devez concevoir cette interface avec soin.
Tout simplement oui
L'application peut charger l'assemblage de béton (dll) au moment de l'exécution. Voir: /programming/465488/can-i-load-a-net-assembly-at-runtime-and-instantiate-a-type-knowing-only-the-na
Si vous devez décharger / charger dynamiquement un tel "pilote", vous devez charger l'assembly dans un AppDomain distinct .
la source
IDevice
interface pour que son appareil puisse être utilisé avec votre application, alors il n'y aurait pas d'autre moyen IMO.