Рефакторинг кода: аутсорсинг подшагов до вспомогательных классов

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

Версия 0

public class ComplicatedTaskDoer{

    public void doComplicatedTask(){
      // lots of complicated code
    }

}

Версия 1:

Разбейте его на несколько более мелких подзадач

public class ComplicatedTaskDoer{

    public void doComplicatedTask(){
      init();
      doSubStepA();
      doB();
      doC();
      wrapUp();
    }
}

Версия 2:

Если это достаточно сложно, передайте подзадачи на аутсорсинг вспомогательным классам. На самом деле я не использую код для интерфейсов в этом случае.

public class ComplicatedTaskDoer{

    public void doComplicatedTask(){
      init();
      subsetpADoerClass.doA();
      classB.doB();
      classC.doC();
      wrapUp();
    }
}

Версия 3:

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

public class ComplicatedTaskController{
    //injected
    List<SomethingHelperComponent> components;
    public void doComplicatedTask(){
      init();
      for(SomethingHelperComponent component : components){
           component.process(commonInput);
      }
      wrapUp();
    }   
}

Мне больше интересна версия 3. В итоге я делал это довольно много раз.

Q1) Есть ли какой-нибудь похожий и, вероятно, более эффективный шаблон? Я ищу не «цепочку обязанностей», поскольку я предпочитаю, чтобы эти компоненты были независимыми (открытыми для обсуждения). Это больше похоже на настраиваемый вариант шаблона метода шаблона.

Q2) Я всегда называл основной класс «SomethingController», а вспомогательные классы - «SomethingHelper» или «SomethingComponent». Недавно я понял, что «контролер» вводит в заблуждение, а «помощник» не информативен.

Было бы действительно полезно получить некоторые идеи о том, как правильно назвать эти классы. Как вы их назвали?

Q3) Считаете ли вы, что рефакторинг был разумным?

Q4) Субъективно. Можно ли оставить некоторые шаги во вспомогательных методах и передать некоторые шаги вспомогательным классам? Обычно я воздерживаюсь от модульного тестирования непубличных методов.

Q5) Считаете ли вы, что вспомогательные классы, т. е. без интерфейсов, являются запахом кода? Могу ли я даже объявить их внутренними классами?


person phanin    schedule 18.06.2014    source источник
comment
Первое, что я обычно делаю, это заменяю метод объектом метода. Рефакторинг в таком классе будет проще.   -  person Seelenvirtuose    schedule 18.06.2014
comment
На самом деле, я считаю, что это довольно нереальная закономерность. При рефакторинге унаследованного кода проблема состоит в том, чтобы сохранить контекст между частями и определить среди них чистый набор параметров.   -  person Leo    schedule 18.06.2014
comment
Я бы охарактеризовал этот вопрос как очень широкий, по которому можно было бы получить несколько предложений. я бы посоветовал разработать что-то разумное, основанное на рассматриваемой проблеме, а не искать несколько решений. иногда решение, которое выглядит слишком простым, может быть правильным подходом, и да, я поддерживаю классы Helper.   -  person vikeng21    schedule 18.06.2014
comment
@Leo обычно версии 3 не предшествует версия 2 и рефакторинг. Я делаю версию 3, если реализую с нуля и вижу закономерность. Например, у меня есть поисковый запрос, и я хочу запустить несколько алгоритмов для его расширения / обогащения и т. Д. Основной класс будет лицом API, тогда как подшаги - это отдельные алгоритмы, и я вижу, что добавляю больше алгоритмов в будущее, чтобы улучшить его дальше.   -  person phanin    schedule 18.06.2014
comment
@phani, если честно, я думаю, что №1 легче читать и поддерживать, если идея состоит в том, чтобы разбить сложную обработку на более мелкие части. №3 напоминает мне паттерн команд, который полезен в некоторых случаях (когда вы можете составлять операции), но обычно это не так.   -  person Leo    schedule 18.06.2014
comment
И я согласен, что вопрос слишком широкий   -  person Leo    schedule 18.06.2014


Ответы (1)


Конфигурация классов

Это законное решение. Иногда это можно увидеть с помощью spring, где частичные задачи реализуют некоторый интерфейс, и с помощью магии Spring вы можете получить список всех реализаций с помощью

@Autowired
List<MyInterface> myParts;

Название шаблона дизайна

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

Именование классов

Я бы выбрал суффикс .*Algorithm

Назовите основной интерфейс, например, DoSomethingComplicatedAlgorithm или DoSomethingComplicatedAlgorithmStep. Классы, реализующие интерфейс, будут называться WhatPartOfAlgorithmIsUsedHere

Вспомогательные классы

Если они позволят вам избежать дублирования кода, и у вас нет лучшей модели предметной области, чем вы можете их использовать. С другой стороны, оставьте это на крайний случай. Может быть небольшой запах кода, но ваше приложение точно не сгорит.

person Marcin Szymczak    schedule 09.09.2015