Статьи

Справиться с методами с множеством параметров

Сейчас я поставлю своего капитана Очевидный Кейп и вкратце напишу, как избавиться от методов с множеством параметров, особенно если некоторые параметры являются необязательными или как-то зависят друг от друга (например, идут парами, один исключает другой и т. Д.) ,

Давайте возьмем простой класс RestClient . Необходимо иметь возможность передавать целевой ресурс, необязательные заголовки HTTP, метод HTTP, тело запроса, тайм-ауты и т. Д. Все они, кроме URL, являются необязательными. Как вы пишете этот класс?

Первое, что приходит в голову, это перегрузка:

1
2
3
4
public <T> T request(String url);
public <T> T request(String url, HttpMethod method, Object body);
public <T> T request(String url, HttpMethod method, Object body, Map<String, String> headers);
public <T> T request(String url, HttpMethod method, Object body, Map<String, String> headers, long timeout);

Хороший? Нет. Потому что вы можете вызвать URL с помощью GET, указав тайм-аут, но не указав тело или заголовки. И всякий раз, когда должен быть добавлен новый параметр (например, для аутентификации), вы должны скопировать все методы и добавить параметр. Проще говоря: вы не можете и не должны иметь перегруженный метод для каждой возможной комбинации параметров.

Как мы должны подойти к проблеме? Есть несколько способов , и я предпочитаю использовать что-то вроде шаблона Builder . Предполагается, что шаблон Builder используется для конструирования объектов и замены конструкторов, принимающих несколько аргументов. Но его философия может быть перенесена на вышеуказанную проблему. Например:

1
public <T> T request(RestCall call);

Что такое RestCall? Это изменяемый объект, который вы конфигурируете, желательно с свободным интерфейсом , чтобы сделать ваш вызов покоя. Все поля имеют геттеры, так что RestClient может получить все поля, в которых нуждается. Использование может выглядеть так:

1
2
client.request(RestCall.to(url).withMethod(HttpMethod.POST)
    .withBody(requestObject).withTimeout(5000));

Он читается как проза, он позволяет вам использовать только один (или очень мало) методов вместо перегрузки для каждой возможной комбинации, и в то же время позволяет вам иметь каждую возможную комбинацию параметров. Метод «to (..)» является простым фабричным методом . Пример реализации метода withX выглядит следующим образом:

1
2
3
4
public RestCall withBody(Object body) {
    this.body = body; //assign a private field
    return this;
}

Вы также можете иметь разумные значения по умолчанию для каждого поля. В этом случае, метод GET, предопределенный тайм-аут по умолчанию.

Этот подход также дает вам возможность указать ограничения. Например, вы не должны разрешать установку тела для запросов GET. Так:

1
2
3
4
5
6
7
8
public RestCall withBody(Object body) {
    if (method == HttpMethod.GET) {
         throw
              new IllegalStateException("Body not supported for GET");
    }
    this.body = body; //assign a private field
    return this;
}

И если два параметра идут вместе, например, вы хотите добавить заголовки один за другим, тогда у вас может быть addHeader(String, String) .

Как правило, этот подход более читабелен и его легче расширять и поддерживать.

Ссылка: Справка по методам со многими параметрами от нашего партнера по JCG Божидара Божанова в техническом блоге Божо .