Jak owinąć usługę, aby była prostsza

11

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, StorageModelktóry jest naszą wewnętrzną reprezentacją Storage.

Co powrócisz w programie mapującym: Storagelub StorageModel? Mamy usługę DataService, StorageServicektó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 Storageobiekt zewnętrzny, a wewnętrzny StorageServicezwraca wewnętrzny StorageModel?
  • A może zwróciłbyś StorageModeljuż opakowanie?
kserafim
źródło
2
Dlaczego nazywasz to opakowaniem? Lepiej szukaj wzoru fasady, mostu i adaptera. Jak rozumiem, opakowanie zapewniłoby wszystkie metody usługi innej firmy - ale nie tego chcesz.
Tobias Otto
@TobiasOtto opakowanie nie musi ujawniać całego zachowania zawiniętego obiektu, zobacz ten artykuł w „Ograniczonym opakowaniu”.
guillaume31

Odpowiedzi:

11

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ą.

doubleYou
źródło
3

W naszym projekcie postanowiłem zawinąć interfejs w klasę i ujawnić tylko metody, których potrzebujemy.

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 Storagejest obcy .

Ale nie jestem pewien, jak powinienem obsługiwać zwracane wartości ...

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:

Laiv
źródło
1

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

MyPocoObjectRepo
    MyPocoObject GetObject(string id);

gdzie MyPocoObject to całkowicie twoje dane i logika biznesowa. Nie powielanie Storage, DataReader ani nic

Ewan
źródło
0

Odpowiedź jest taka, że ​​zależy to od tego, czy kiedykolwiek potrzebujesz dostępu Storagebezpośrednio z klasy, która nie jest StorageModel.

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ć Storagebezpośrednio, oznacza to, że może zaistnieć potrzeba zwrotu w Storagezależności od sytuacji. Można by argumentować za tym, aby zobowiązać się do Storageużywania tego, StorageModelco 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 StorageModelw swoim programie, a nie Storage.

Neil
źródło