Jesteśmy zależni od usługi innej firmy, która ujawnia gigantyczny interfejs, którego potrzebujemy tylko 3 metody. Dodatkowo interfejs często się zmienia ...
W naszym projekcie postanowiłem zawinąć interfejs w klasę i ujawnić tylko metody, których potrzebujemy.
Ale nie jestem pewien, jak powinienem obsługiwać zwracane wartości ... Interfejs zwraca obiekt typu Storage
. Wewnętrznie mamy typ, StorageModel
który jest naszą wewnętrzną reprezentacją Storage
.
Co powrócisz w programie mapującym: Storage
lub StorageModel
? Mamy usługę DataService, StorageService
która uzyskuje zależność od wstrzykniętego opakowania.
Obecnie robię to w zasadzie tak:
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);
}
}
}
Co byś powiedział:
- Czy to dobrze, jak powyżej, że opakowanie zwraca
Storage
obiekt zewnętrzny, a wewnętrznyStorageService
zwraca wewnętrznyStorageModel
? - A może zwróciłbyś
StorageModel
już opakowanie?
Odpowiedzi:
Według mnie opakowanie powinno zajmować się wszystkimi rzeczami związanymi z biblioteką zewnętrzną. Oznacza to, że publiczny interfejs Opakowania nie może nazywać żadnych typów zewnętrznych.
Mapowanie typów zewnętrznych do odpowiednich typów aplikacji jest częścią obowiązków opakowania. Jeśli nie jest to trywialna operacja, możesz użyć różnych dostępnych narzędzi do rozłożenia problemu, np. Wstrzyknięcie obiektu translatora. Tłumacz musi jednak nadal stanowić część modułu opakowania i żadna inna część aplikacji nie może od tego zależeć.
W ten sposób reszta aplikacji jest całkowicie odporna nie tylko na zmiany w bibliotece, ale także na zamianę biblioteki na inną.
źródło
W porządku. Jest to również znane jako adapter .
Wybierasz wzorzec adaptera , więc celem jest przekształcenie jednego interfejsu (modelu biblioteki) w inny (model domeny). Jeśli więc coś z tego pierwszego osiągnie model domeny, adapter nie spełnia swojego celu .
Zgodnie z poprzednimi argumentami adapter powinien zwrócić wartość
StorageModel
.Ostatecznie Twoja domena „mówi” w określonym języku, w którym
Storage
jest obcy .Kluczem tutaj jest wiedzieć, z jakiego powodu owijasz / dostosowujesz bibliotekę .
Wzory adaptera, dekoratora i elewacji mogą mieć podobieństwa, ale są dość różne. Tak różne, jak problemy, które rozwiązują.
To powiedziawszy, możesz być zainteresowany:
Wzór elewacji (ukrywanie złożoności)
Wzór dekoratora (rozszerzenie interfejsu) . Kiedy z niego korzystać
Różnice między wzorcem adaptera a wzorcem proxy .
Co to jest warstwa antykorupcyjna i jak jest używana (ukrywanie niskiej jakości i niechlujnego kodu)
źródło
Nie można skutecznie owinąć biblioteki, powielając ją.
To, co powinieneś owinąć, to korzystanie z biblioteki, a to oznacza, że nie eksponujesz jej obiektów, w tym przypadku Storage. Nie próbuj ich duplikować.
Korzystaj z biblioteki, ale przechowuj ją. Więc w twoim przypadku, zakładając, że używasz StorageService do przechowywania rzeczy, powinieneś zapakować je w repozytoria
gdzie MyPocoObject to całkowicie twoje dane i logika biznesowa. Nie powielanie Storage, DataReader ani nic
źródło
Odpowiedź jest taka, że zależy to od tego, czy kiedykolwiek potrzebujesz dostępu
Storage
bezpośrednio z klasy, która nie jestStorageModel
.Jeśli zamierzasz zawinąć bibliotekę, sensowne jest również zawinięcie zwróconego przez nią obiektu, aby umożliwić przyszłe korekty zmian wprowadzonych przez bibliotekę w przyszłości. Jeśli jednak kiedykolwiek będziesz musiał użyć
Storage
bezpośrednio, oznacza to, że może zaistnieć potrzeba zwrotu wStorage
zależności od sytuacji. Można by argumentować za tym, aby zobowiązać się doStorage
używania tego,StorageModel
co prawdopodobnie chcesz zachować spójność w całym programie.Zdecydowanie polecam zawinięcie zarówno interfejsu, jak i zwróconego obiektu, jeśli jeszcze tego nie robisz, ale to ma sens tylko wtedy, gdy używasz tylko
StorageModel
w swoim programie, a nieStorage
.źródło