¿Cómo envuelvo un servicio para que sea más simple?

11

Tenemos una dependencia a un servicio de terceros que expone una interfaz gigantesca de la que solo necesitamos como 3 métodos. Además, la interfaz cambia con frecuencia ...

He decidido incluir la interfaz en una clase en nuestro proyecto y solo exponer los métodos que necesitamos.

Pero no estoy seguro de cómo debo manejar los valores de retorno ... La interfaz devuelve un objeto de tipo Storage. Internamente tenemos un tipo StorageModelque es nuestra representación interna de a Storage.

¿Qué devolverías en el mapeador: Storageo StorageModel? Tenemos un DataService StorageServiceque obtiene una dependencia del contenedor inyectado.

Actualmente lo estoy haciendo básicamente así:

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

Qué dirías:

  • ¿Es bueno como el anterior, que el contenedor devuelve el Storageobjeto externo y el interno StorageServicedevuelve el interno StorageModel?
  • ¿O ya devolverías un StorageModelenvoltorio?
xeraphim
fuente
2
¿Por qué lo llamas envoltorio? Busque mejor el patrón de fachada, puente y adaptador. Según tengo entendido, un contenedor proporcionaría todos los métodos del servicio de terceros, pero eso no es lo que desea.
Tobias Otto
@TobiasOtto un contenedor no necesita exponer todo el comportamiento del objeto envuelto, vea este artículo en "Un contenedor limitado".
guillaume31

Respuestas:

11

En mi opinión, el contenedor debe tratar con todas las cosas relacionadas con la biblioteca externa. Esto significa que la interfaz pública del Wrapper no debe nombrar ningún tipo externo.

La asignación de tipos externos a los tipos respectivos de su aplicación es parte de las tareas del contenedor. Si no se trata de una operación trivial, puede utilizar las diversas herramientas disponibles para descomponer el problema, por ejemplo, inyectar un objeto traductor. Sin embargo, el traductor aún debe ser parte de su módulo contenedor y ninguna otra parte de su aplicación puede depender de él.

De esta manera, el resto de su aplicación es completamente inmune no solo a los cambios en la biblioteca, sino también a los reemplazos de la biblioteca por otro.

te doblo
fuente
3

He decidido incluir la interfaz en una clase en nuestro proyecto y solo exponer los métodos que necesitamos.

Está bien. Esto también se conoce como Adaptador .

Usted elige el patrón Adaptador , por lo que el objetivo aquí es transformar una interfaz (modelo de biblioteca) en otra (modelo de dominio). Entonces, si algo del primero alcanza el modelo de dominio, el adaptador está fallando en su propósito .

Según los argumentos anteriores, el adaptador debe devolver el StorageModel.

En última instancia, su dominio "habla" un idioma específico, donde Storagees un extraño .

Pero no estoy seguro de cómo debo manejar los valores de retorno ...

La clave aquí es saber por qué razón está envolviendo / adaptando la biblioteca .

Los patrones de Adaptador, Decorador, Fachada pueden tener similitudes, pero son bastante diferentes. Tan diferentes como los problemas que resuelven.

Dicho esto, es posible que también te interese:

Laiv
fuente
1

No puede envolver una biblioteca de manera efectiva al duplicarla.

Lo que debe envolver es su uso de la biblioteca y eso significa no exponer sus objetos, en este caso Almacenamiento. No intentes duplicarlos tampoco.

Use la biblioteca, pero manténgala contenida. Entonces, en su caso, suponiendo que esté utilizando StorageService para almacenar cosas, debe envolverlo en repositorios

MyPocoObjectRepo
    MyPocoObject GetObject(string id);

donde MyPocoObject es completamente su lógica de datos y negocios. No es una duplicación de almacenamiento o un DataReader ni nada

Ewan
fuente
0

La respuesta es que depende de si alguna vez necesita acceder Storagedirectamente desde una clase que no lo es StorageModel.

Si va a ajustar la biblioteca, tiene sentido también ajustar el objeto devuelto por ella para permitirle realizar pruebas futuras de los cambios realizados por la biblioteca en el futuro. Sin embargo, si alguna vez necesita usar Storagedirectamente, significa que puede ser necesario regresar de Storageacuerdo con la situación. Podría argumentarse que obligar a que el Storageuso aquí sea StorageModelcomo es probable que desee permanecer constante en todo su programa.

Recomiendo encarecidamente que ajuste la interfaz y el objeto devuelto si aún no lo está haciendo, aunque de nuevo, eso solo tiene sentido si solo está usando StorageModeltodo su programa y no Storage.

Neil
fuente