Самый простой способ передачи большого количества параметров в Java

Мой основной язык - TypeScript, и он позволяет упаковывать большое количество аргументов в объекты:

function initializeApplication(options: {
  projectBuildingMode: string,
  enableDebugging: boolean,
  projectType: string,
  // ... и ещё несколько десятков
}): void { }

Что есть в Java максимально близкое по концепции к приведённому выше коду?

Проблема

void initializeApplication(String projectBuildingMode, Boolean enableDebugging, String projectType, /* и ещё пару десятков ... */)

Что, если мы заходим добавить в середину один-два параметра? Придётся переписывать места вызова этого метода.


Ответы (3 шт):

Автор решения: Ivan Dyominov

Вы можете создать класс который можно использовать в качестве аргумента и в случае добавления полей, вам нужно будет изменять только его, если вам не нужно будет модифицировать под новые поля другие функции, то при помощи конструкторов, значений по умолчанию и get/set вы можете избежать переписывания старых кусков.

→ Ссылка
Автор решения: Санаев

Можно попробовать использовать @Builder от ломбока, как подсказал @Miron или воспользоваться перечислением с помощью type... Ниже привел пример кода

@Builder
@ToString
public class Animal {
    private String cat;
    private String dog;
    private String cow;
    private String giraffe;
    private String bear;
}

class Main {
    public static void main(String[] args) {
        Animal animal = Animal
                .builder()
                .bear("Медведь")
                .cat("Мурка")
                .dog("Шарик")
                .build();
        printAnimal(animal);

        printAnimal("Медведь", " Кот", " Бык");
    }

    private static void printAnimal(Animal animal) {
        System.out.println(animal.toString());
    }

    private static void printAnimal(String... value) {
        Stream.of(value).forEach(System.out::print);
    }
}
→ Ссылка
Автор решения: Боков Глеб

На основе подсказок @Дмитрий, @IvanDyominov и @Miron разработал такой билдер:

public class Person {

  private String familyName;
  private String givenName;


  public Person(ParametersObject parametersObject) {
    parametersObject.initializeSpecifiedFields(this);
  }


  public static ParametersObject parametersObject() {
    return new Person.ParametersObject();
  }


  public static class ParametersObject {

    private String familyName;
    private String givenName;


    public void initializeSpecifiedFields(Person person) {
      person.familyName = this.familyName;
      person.givenName = this.givenName;
    }


    public ParametersObject setFamilyName(String familyName) {
      this.familyName = familyName;
      return this;
    }

    public ParametersObject setGivenName(String givenName) {
      this.givenName = givenName;
      return this;
    }
  }
}

Теперь конструировать Person можно так:

new Person(Person.parametersObject()
  .setFamilyName("Jonson")
  .setGivenName("John")
);

Недостатки решения

  1. Пока не знаю, как обязать других программистов, которые будут создавать инстанс Person, инициализировать обязательные поля. В теории, если можно как-то обязать вызвать метод, то проблема решаема.
  2. Если понадобится облепить класс Person сеттерами, то они могут быть один в один с сеттерами с ParametersObject (если мы пожелаем цепную API). Разница лишь в том, что они возвращают разный this. Создавать абстрактный класс, общий для Person и ParametersObject не хочется - хотелось бы, чтобы всё было инкапсулировано в одном классе (то есть, чтобы сущность Person была основополагающей и самостоятельной).

Конструктивная критика решения приветствуется!

→ Ссылка