Статьи

Функция хамелеона

В «Докторе Кто» персонаж Камелион был роботом, который мог принимать любую форму. Физическая опора, которую они использовали, якобы была очень хлопотной и понималась только ее создателем, который не был рядом, чтобы помочь исправить это.

Так что к функции Chamelion …

Рассмотрим этот код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
public List<Document> getAllDocuments(Request request, int userId, String field) {
   Query q = createQueryFrom(request);
 
   switch (field) {
      case "title":
          q.addCriteria(Criteria.where("title").is(request.getTitle());
          break;
 
      case "name":
          q.addCriteria(Criteria.where("name").is(request.getName());
          break;
  
      default:
          throw new IllegalArgumentException("Bad field: " + field);
   }
 
   return q;
}

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

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

Что не так с этой функцией?

Я скажу тебе, что не так …

Это не функция. Это две функции. Смотрите также оба вида музыки .

Код вызова может выглядеть так:

1
2
3
4
5
// one call site
getAllDocuments(request, id, "title");
 
// another
getAllDocumetns(request, id, "name");

Мы используем выбор строки, чтобы контролировать половину потока одной функции.

Хуже того … нам нужно исключение, чтобы бросить, когда какой-то вызывающий изобрел строку, о которой мы никогда не слышали

Давайте просто сделаем рефакторинг на секунду:

01
02
03
04
05
06
07
08
09
10
11
public List<Document> getAllDocumentsByTitle(Request request, int userId) {
   Query q = createQueryFrom(request);
   q.addCriteria(Criteria.where("title").is(request.getTitle());
   return q;
}
 
public List<Document> getAllDocumentsByName(Request request, int userId) {
   Query q = createQueryFrom(request);
   q.addCriteria(Criteria.where("name").is(request.getName());
   return q;
}

Разделив это на две функции, он самодокументируется, его легче отслеживать и ему не нужно обрабатывать мошеннические строки. Это, вероятно, немного быстрее, но это не очень важный драйвер.

Но как насчет дублирования?

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

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

Смотрите оригинальную статью здесь: функция хамелеона

Мнения, высказанные участниками Java Code Geeks, являются их собственными.