Comment encapsuler un service pour qu'il soit plus simple

11

Nous sommes dépendants d'un service tiers qui expose une interface gigantesque dont nous n'avons besoin que de 3 méthodes. De plus, l'interface change fréquemment ...

J'ai décidé d'envelopper l'interface dans une classe de notre projet et d'exposer uniquement les méthodes dont nous avons besoin.

Mais je ne sais pas comment je dois gérer les valeurs de retour ... L'interface renvoie un objet de type Storage. Nous avons en interne un type StorageModelqui est notre représentation interne d'un Storage.

Que voudriez-vous retourner dans le mappeur: Storageou StorageModel? Nous avons un DataService StorageServicequi obtient une dépendance du wrapper injecté.

Actuellement, je le fais essentiellement comme ceci:

public class StorageService 
{
    private readonly IExternalStorageWrapper externalStorageWrapper;

    public StorageService(IExternalStorageWrapper externalStorageWrapper)
    {
        this.externalStorageWrapper = externalStorageWrapper;
    }

    public StorageModel GetStorage(int storageId)
    {
        return this.externalStorageWrapper.GetStorage(storageId).ConvertToStorageModel();
    }
}

public class ExternalStorageWrapper : IExternalStorageWrapper
{
    public Storage GetStorage(int storageId)
    {
        using(var ext = new ExternalStorage())
        {
            return ext.GetStorage(storageId);
        }
    }
}

Que dirais-tu:

  • Est-ce bien comme ci-dessus, que le wrapper retourne l' Storageobjet externe et que le interne StorageServicerenvoie le interne StorageModel?
  • Ou retourneriez-vous déjà un StorageModeldans l'emballage?
xéraphins
la source
2
Pourquoi le nommez-vous un emballage? Mieux vaut chercher le modèle de façade, de pont et d'adaptateur. Si je comprends bien, un wrapper fournirait toutes les méthodes du service tiers - mais ce n'est pas ce que vous voulez.
Tobias Otto
@TobiasOtto un wrapper n'a pas besoin d'exposer tout le comportement de l'objet enveloppé, voir cet article dans "Un wrapper limité".
guillaume31

Réponses:

11

À mon avis, le wrapper devrait traiter de tout ce qui concerne la bibliothèque externe. Cela signifie que l'interface publique du wrapper ne doit nommer aucun type externe.

Le mappage de types externes aux types respectifs de votre application fait partie des fonctions de l'encapsuleur. Si ce n'est pas une opération banale, vous pouvez utiliser les différents outils disponibles pour décomposer le problème, par exemple en injectant un objet traducteur. Cependant, le traducteur doit toujours faire partie de votre module wrapper et aucune autre partie de votre application ne peut en dépendre.

De cette façon, le reste de votre application est complètement immunisé non seulement aux changements dans la bibliothèque, mais aussi aux remplacements de la bibliothèque pour une autre.

doubleYou
la source
3

J'ai décidé d'envelopper l'interface dans une classe de notre projet et d'exposer uniquement les méthodes dont nous avons besoin.

C'est bon. Ceci est également appelé adaptateur .

Vous choisissez le modèle d' adaptateur , donc l'objectif ici est de transformer une interface (modèle de bibliothèque) en une autre (modèle de domaine). Donc, si quelque chose de l'ancien atteint le modèle de domaine, l'adaptateur ne parvient pas à son objectif .

Selon les arguments précédents, l'adaptateur doit renvoyer le StorageModel.

En fin de compte, votre domaine "parle" une langue spécifique, où Storageest un étranger .

Mais je ne sais pas comment je dois gérer les valeurs de retour ...

La clé ici est de savoir pour quelle raison vous enveloppez / adaptez la bibliothèque .

Les modèles d'adaptateur, de décorateur et de façade peuvent avoir des similitudes, mais ils sont assez différents. Aussi différents que les problèmes qu'ils résolvent.

Cela dit, vous pourriez également être intéressé par:

Laiv
la source
1

Vous ne pouvez pas envelopper efficacement une bibliothèque en la dupliquant.

Ce que vous devez envelopper est votre utilisation de la bibliothèque et cela signifie ne pas l'exposer aux objets, dans ce cas, le stockage. N'essayez pas non plus de les dupliquer.

Utilisez la bibliothèque, mais gardez-la contenue. Donc, dans votre cas, en supposant que vous utilisez le StorageService pour stocker des choses, vous devez l'envelopper dans des référentiels

MyPocoObjectRepo
    MyPocoObject GetObject(string id);

où MyPocoObject est entièrement vos données et votre logique métier. Pas une duplication du stockage ou d'un DataReader ou quoi que ce soit

Ewan
la source
0

La réponse est que cela dépend si vous avez ou non besoin d'accéder Storagedirectement à partir d'une classe qui ne l'est pas StorageModel.

Si vous allez encapsuler la bibliothèque, il est logique d'envelopper également l'objet renvoyé par celle-ci pour vous permettre de modifier à l'avenir les modifications apportées par la bibliothèque à l'avenir. Cependant, si vous devez utiliser Storagedirectement, cela signifie qu'il peut être nécessaire de revenir en Storagefonction de la situation. Un argument pourrait être invoqué pour obliger l' Storageutilisation ici à être StorageModeltelle que vous voulez probablement rester cohérente tout au long de votre programme.

Je vous recommande fortement d'envelopper à la fois l'interface et l'objet retourné si vous ne le faites pas déjà, mais là encore, cela n'a de sens que si vous utilisez uniquement StorageModeltout au long de votre programme et non Storage.

Neil
la source