Как структурировать сложные объекты со связанными полями, которые необходимо инициализировать одновременно

Я реализую API, и я продолжаю сталкиваться с этой проблемой, я думаю, что что-то не так с моим основным дизайном, но я не уверен, что именно, и я чувствую себя подавленным принципами дизайна.

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

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

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

class Person {
    ClientToGetClothing clothingClient;

    Pants pants;
    Shirt shirt;
    Fabric shirtFabric;
    Fabric pantsFabric;

    public Person(ClientToGetClothing clothingClient) {
         this.clothingClient = clothingClient;
    }

    private void populateClothing() {
         PantsResponse pantsInfo = clothingClient.retrievePantsInfo();
         this.pants = pantsInfo.getPants();

         ShirtResponse shirtInfo = clothingClient.retrieveShirtInfo();
         this.shirt = pantsInfo.getShirt();

         // do some more things with my pants + shirt and assign results to more fields, calculate the fabric in this example

    }

    public Shirt getShirt() {
        if (shirt == null) {
            populateClothing;
        }
        return this.shirt;
    }
    // ...
}

person Tristan Sparks    schedule 11.07.2019    source источник
comment
Почему бы не получить необходимые компоненты из внешнего API заранее и не передать их конструктору (Разделение задач &Инверсия управления)? В сочетании с Builder шаблоном это может привести к созданию довольно читаемого кода. Кроме того, этот вопрос лучше подходит для Code Review.   -  person Turing85    schedule 12.07.2019


Ответы (1)


Во-первых, я бы отделил объект ClothingClient от объекта Person. Попросите фабрику выполнить заполнение атрибутов, а затем вернуть класс человека. https://en.wikipedia.org/wiki/Factory_method_pattern#Java

person Arpan Kanthal    schedule 11.07.2019
comment
Я бы сказал, что эта операция слишком сложна для фабрики, и поэтому вместо этого используйте билдер. - person Turing85; 12.07.2019