Temos uma dependência de um serviço de terceiros que expõe uma interface gigantesca da qual precisamos apenas de três métodos. Além disso, a interface muda frequentemente ...
Decidi agrupar a interface em uma classe em nosso projeto e apenas expor os métodos que precisamos.
Mas não tenho certeza de como devo lidar com os valores retornados ... A interface retorna um objeto do tipo Storage
. Internamente, temos um tipo StorageModel
que é nossa representação interna de a Storage
.
O que você retornaria no mapeador: Storage
ou StorageModel
? Temos um DataService StorageService
que obtém uma dependência do wrapper injetado.
Atualmente eu estou fazendo isso basicamente assim:
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);
}
}
}
O que você diria:
- É bom como acima, que o wrapper retorne o
Storage
objeto externo e o internoStorageService
retorne o internoStorageModel
? - Ou você já retornaria um
StorageModel
no invólucro?
Respostas:
Na minha opinião, o wrapper deve lidar com todas as coisas relacionadas à biblioteca externa. Isso significa que a interface pública do Wrapper não deve nomear nenhum tipo externo.
O mapeamento de tipos externos para os respectivos tipos de seu aplicativo faz parte das tarefas do wrapper. Se esta não é uma operação trivial, você pode usar as várias ferramentas disponíveis para decompor o problema, por exemplo, injetando um objeto tradutor. No entanto, o tradutor ainda deve fazer parte do seu módulo wrapper e nenhuma outra parte do seu aplicativo pode depender dele.
Dessa forma, o restante do seu aplicativo é completamente imune não apenas a alterações na biblioteca, mas também a substituições da biblioteca por outra.
fonte
Isso está ok. Isso também é conhecido como adaptador .
Você escolhe o padrão do adaptador , portanto, o objetivo aqui é transformar uma interface (modelo de biblioteca) em outra (modelo de domínio). Portanto, se algo do anterior atingir o modelo de domínio, o adaptador falhará em seu objetivo .
De acordo com os argumentos anteriores, o adaptador deve retornar o
StorageModel
.Por fim, seu domínio "fala" um idioma específico, onde
Storage
é um estranho .A chave aqui é saber por que motivo você está agrupando / adaptando a biblioteca .
Os padrões de adaptador, decorador e fachada podem ter semelhanças, mas são bastante diferentes. Tão diferentes quanto os problemas que eles resolvem.
Dito isto, você também pode estar interessado em:
Padrão de fachada (ocultando complexidade)
Padrão decorador (aprimoramento da interface) . Quando usá-lo
Diferenças entre o padrão do adaptador e o padrão de proxy .
O que é uma camada anticorrupção e como é usada (ocultando código de baixa qualidade e desarrumado)
fonte
Você não pode efetivamente agrupar uma biblioteca duplicando-a.
O que você deve agrupar é o uso da biblioteca e isso significa não expor seus objetos, neste caso Armazenamento. Também não tente duplicá-los.
Use a biblioteca, mas mantenha-a contida. Portanto, no seu caso, supondo que você esteja usando o StorageService para armazenar coisas que você deve agrupar em repositórios
onde MyPocoObject é inteiramente sua lógica de dados e negócios. Não é uma duplicação de armazenamento ou um DataReader ou qualquer coisa
fonte
A resposta é que depende se você precisa ou não acessar
Storage
diretamente de uma classe que não éStorageModel
.Se você deseja agrupar a biblioteca, faz sentido também agrupar o objeto retornado por ela para permitir futuras alterações de prova feitas pela biblioteca no futuro. No entanto, se você precisar usar
Storage
diretamente, isso significa que pode haver necessidade de retornar deStorage
acordo com a situação. Pode-se dizer um argumento para obrigar oStorage
uso aqui a ser oStorageModel
que você provavelmente deseja manter consistente durante todo o programa.Eu recomendo fortemente que você envolva a interface e o objeto retornado, se ainda não o estiver fazendo, no entanto, isso só faz sentido se você estiver usando apenas
StorageModel
o programa e não o fizerStorage
.fonte