Шаблон для разрыва внешних вызовов API? - PullRequest
0 голосов
/ 11 июня 2019

Я пытаюсь сосредоточиться на том, как бы я решил эту конкретную проблему. У нас есть внешний API, который выполняет некоторую логику и возвращает результат этой логики. К сожалению, API возвращает новый объект в результате, в отличие от той части, которая мне интересна. Например, код будет выглядеть примерно так:

public class ComplexObject {
    //lots of fields
}

public interface LogicApplier {
    LogicResult applyLogic(ComplexObject obj);
}

public class LogicResult {
    ComplexObject result;

    public ComplexObject getResult();
}

public class FirstImplementation {

    private LogicApplier _applier;

    public Implementation(LogicApplier applier) {
        _applier = applier;
    }

    public ComplexObject mainImplementation (ComplexObject apply) {
        LogicResult logicResult = _applier.applyLogic(apply);

        ComplexObject newComplexObject = logicResult.getResult();

        //Do some other stuff with new ComplexObject
    }
}

Итак, вопрос в том, как лучше всего ограничить «власть» LogicApplier над FirstImplementation? Например, наша мотивация для вызова логики в первую очередь состоит в том, чтобы получить пропущенное поле, скажем, «имя». Это поле может потенциально отличаться, скажем, во SecondImplementation, где эта реализация теперь пытается получить «уличный адрес» из LogicApplier API. Однако ничто не мешает LogicApplier изменить другое поле, например, «idNumber».

Лучше ли это решить путем добавления интерфейса для наших конкретных реализаций и сопоставления полей вручную? Что-то вроде:

public interface SecondImplementationLogicApplier {

    public String deriveAddress(ComplexObject o);
}

public class LimitedImplementationLogicApplier implements FirstImplementationLogicApplier, SecondImplementationLogicApplier {
    LogicApplier _applier;
    public LimitedImplementationLogicApplier(LogicApplier applier) {
        _applier = applier;
    }

    public String deriveFirstName(ComplexObject o) {
     LogicResult res = _applier.applyLogic(o);
     return res.firstName;
    }


    public String deriveFirstName(ComplexObject o) {
     LogicResult res = _applier.applyLogic(o);
     return res.address;
    }

}

1 Ответ

1 голос
/ 11 июня 2019

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

Похоже, ваш ComplexObject изменчив. Я хотел бы спрятать его за неизменяемым интерфейсом (у которого нет никаких установщиков или способов изменить выставленный объект) и передать неизменяемый интерфейс в ваш LimitedImplementationLogicApplier, чтобы у него не было шанса изменить ComplexObject.

Если вашему API требуется тип ComplexObject и вы не можете его изменить, для предотвращения мутации вы можете:

Вариант 1

Создайте clone вашего базового ComplexObject экземпляра и передайте его в API. После получения результата вы обновляете необходимые поля в нетронутом экземпляре base. Это будет хорошо работать, если ComplexObject является «вещью в себе» и изменения в его состоянии не имеют побочных эффектов вне экземпляра класса, таких как изменение баз данных или влияние на другое состояние.

Если мутация ComplexObject имеет побочные эффекты или may have them in future, то это настоящая проблема.

Вариант 2

Унаследуйте класс ReadonlyComplexObject от ComplexObject и передайте его в API. В ReadonlyComplexObject вы подавите все поведение родителя, чтобы предотвратить изменение.

Это, на мой взгляд, хакерство и позже создаст дополнительную работу - если ComplexObject будет расширен новыми свойствами, позже вам нужно будет внести изменения в ReadonlyComplexObject, иначе мутация все равно будет происходить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...