Как мне обернуть сервис, чтобы он был проще

11

У нас есть зависимость от стороннего сервиса, который предоставляет гигантский интерфейс, который нам нужен только как 3 метода. Кроме того, интерфейс часто меняется ...

Я решил обернуть интерфейс в класс в нашем проекте и раскрыть только те методы, которые нам нужны.

Но я не уверен, как я должен обрабатывать возвращаемые значения ... Интерфейс возвращает объект типа Storage. У нас внутри есть тип, StorageModelкоторый является нашим внутренним представлением Storage.

Что бы вы вернули в картограф: Storageили StorageModel? У нас есть DataService, StorageServiceкоторый получает зависимость от вложенной оболочки.

В настоящее время я делаю это в основном так:

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

Что бы вы сказали:

  • Это хорошо, как и выше, что оболочка возвращает внешний Storageобъект, а внутренний StorageServiceвозвращает внутренний StorageModel?
  • Или вы бы вернули StorageModelв обертке уже?
xeraphim
источник
2
Почему вы называете это оберткой? Лучше поищи рисунок фасада, моста и адаптера. Как я понимаю, обертка будет предоставлять все методы стороннего сервиса - но это не то, что вы хотите.
Тобиас Отто
@TobiasOtto оболочка не должна раскрывать все поведение обернутого объекта, см. Эту статью в разделе «Ограниченная оболочка».
guillaume31

Ответы:

11

По моему мнению, оболочка должна иметь дело со всеми вещами, связанными с внешней библиотекой. Это означает, что открытый интерфейс Wrapper не должен называть какие-либо внешние типы.

Сопоставление внешних типов с соответствующими типами вашего приложения является частью обязанностей оболочки. Если это не тривиальная операция, вы можете использовать различные инструменты, доступные для декомпозиции проблемы, например внедрение объекта-переводчика. Однако переводчик все еще должен быть частью вашего модуля-оболочки, и никакая другая часть вашего приложения не может зависеть от него.

Таким образом, остальная часть вашего приложения будет полностью защищена не только от изменений в библиотеке, но и от замены библиотеки другой.

doubleYou
источник
3

Я решил обернуть интерфейс в класс в нашем проекте и раскрыть только те методы, которые нам нужны.

Это нормально. Это также называется адаптером .

Вы выбираете шаблон адаптера , поэтому цель здесь - преобразовать один интерфейс (модель библиотеки) в другой (модель предметной области). Таким образом, если что-то из первого достигает доменной модели, адаптер не справляется со своей задачей .

Согласно предыдущим аргументам адаптер должен возвращать StorageModel.

В конечном счете, ваш домен «говорит» язык конкретно, где Storageэто незнакомец .

Но я не уверен, как я должен обрабатывать возвращаемые значения ...

Ключевым моментом здесь является знать, по какой причине вы упаковываете / адаптируете библиотеку .

Шаблоны Adapter, Decorator, Facade могут иметь сходство, но они довольно разные. Как и проблемы, которые они решают.

Тем не менее, вы также можете быть заинтересованы в:

LAIV
источник
1

Вы не можете эффективно обернуть библиотеку, дублируя ее.

То, что вам следует обернуть, - это использование библиотеки, а это означает, что она не раскрывает объекты, в данном случае Storage. Не пытайтесь их дублировать.

Используйте библиотеку, но храните ее. Так что в вашем случае, если вы используете StorageService для хранения вещей, вы должны обернуть его в репозитории

MyPocoObjectRepo
    MyPocoObject GetObject(string id);

где MyPocoObject - полностью ваши данные и бизнес-логика. Не дублирование хранилища или DataReader или чего-либо

Ewan
источник
0

Ответ в том, что это зависит от того, нужен ли вам доступ Storageнапрямую из класса, который не нужен StorageModel.

Если вы собираетесь обернуть библиотеку, имеет смысл также обернуть возвращаемый ею объект, чтобы в будущем вы могли проверить изменения, внесенные библиотекой. Однако, если вам когда-либо понадобится использовать Storageнапрямую, это может означать, что вам может понадобиться вернуться в Storageзависимости от ситуации. Можно привести аргумент в пользу того, чтобы Storageиспользование здесь было таким, StorageModelкаким вы, вероятно, хотите оставаться последовательным во всей вашей программе.

Я настоятельно рекомендую вам обернуть интерфейс и возвращаемый объект, если вы этого еще не сделали, хотя, опять же, это имеет смысл, только если вы используете только StorageModelв своей программе, а неStorage .

Нил
источник