Как вы преобразуете класс Бога?

Кто-нибудь знает лучший способ рефакторинга объекта Бога?

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

4 ответа

Решение

Это как Дженга. Вам понадобится терпение и твердая рука, иначе придется воссоздавать все с нуля. Что само по себе неплохо - иногда нужно выбросить код.

Другие советы:

  • Подумайте, прежде чем извлекать методы: на каких данных работает этот метод? Какая ответственность у него есть?
  • Попробуйте сначала сохранить интерфейс класса "бог" и делегировать вызовы новым извлеченным классам. В конце класс бога должен быть чистым фасадом без собственной логики. Тогда вы можете оставить его для удобства или выбросить и начать использовать только новые классы
  • Модульные тесты помогают: пишите тесты для каждого метода перед его извлечением, чтобы гарантировать, что вы не нарушите функциональность

Я предполагаю, что "Объект Бога" означает огромный класс (измеряется в строках кода).

Основная идея состоит в том, чтобы выделить части своих функций в другие классы.

Для того, чтобы найти их, вы можете искать

  • поля / параметры, которые часто используются вместе. Они могут переехать вместе в новый класс

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

  • примитивные типы (int, String, boolean). Они часто являются действительно ценными объектами до их выхода. Как только они являются ценностным объектом, они часто привлекают методы.

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

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

  • Тесты: Подготовьте исчерпывающий набор тестов, которые вы можете часто выполнять. Будьте предельно осторожны с изменениями, которые вы делаете без тестов. Я делаю это, но ограничиваю их такими вещами, как метод извлечения, который я могу сделать полностью одним действием IDE.

  • Контроль версий: вы хотите иметь контроль версий, который позволит вам фиксировать каждые 2 минуты, не замедляя работу. SVN на самом деле не работает. Git делает.

  • Метод Микадо: Идея метода Микадо - попытаться измениться. Если это работает отлично. Если не принять к сведению, что ломается, добавьте их в качестве зависимости от изменения, с которым вы начали. Откат тебе изменений. На полученном графике повторите процесс с узлом, который еще не имеет зависимостей. http://mikadomethod.wordpress.com/book/

Согласно книге Ланцы и Маринеску «Объектно-ориентированные метрики на практике», проектный недостаток класса Бога относится к классам, которые стремятся централизовать интеллект системы. Бог-класс выполняет слишком много работы сам по себе, делегируя лишь незначительные детали набору тривиальных классов и используя данные из других классов.

Обнаружение класса бога основано на трех основных характеристиках:

  1. Они активно обращаются к данным других более простых классов либо напрямую, либо с помощью методов доступа.
  2. Они большие и сложные
  3. У них много некоммуникативного поведения, т. Е. Между методами, принадлежащими к этому классу, существует низкая согласованность.

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

Метод Split Up God Class из книги «Шаблоны объектно-ориентированного реинжиниринга» предлагает постепенно перераспределять обязанности God Class либо на его сотрудничающие классы, либо на новые классы, которые извлекаются из God Class.

В книге «Эффективная работа с унаследованным кодом» представлены некоторые методы, такие как Sprout Method, Sprout Class, Wrap Method, чтобы иметь возможность тестировать унаследованные системы, которые могут использоваться для поддержки рефакторинга классов God.

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

Таким образом, каждый новый класс будет меньше и более согласованным (это означает, что все их методы будут работать с аналогичными свойствами класса). Более того, будет меньше зависимости для каждого нового сгенерированного нами класса. После этого мы можем еще больше уменьшить эти зависимости, так как теперь мы можем лучше понимать код.

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

Итак, ваш класс будет выглядеть примерно так:

      public class LoginManager(){
validateUser(String userId, String hashedPassword){
//Around 150 lines of code below

}
public class LoginManager(){
validateUser(String userId, String hashedPassword){
//Around 150 lines of code below

}

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

Здесь действительно две темы:

  • Учитывая класс Бога, как его члены рационально делятся на подмножества? Фундаментальная идея состоит в том, чтобы сгруппировать элементы по концептуальной связности (часто на это указывает частое совместное использование в клиентских модулях) и по вынужденным зависимостям. Очевидно, детали этого специфичны для системы, подвергаемой рефакторингу. Результатом является желаемое разделение (набор групп) элементов класса Бога.

  • Учитывая желаемый раздел, на самом деле внесение изменений. Это сложно, если кодовая база имеет какой-либо масштаб. Делая это вручную, вы почти вынуждены сохранять класс God, в то время как вы изменяете его методы доступа, чтобы вместо этого вызывать новые классы, сформированные из разделов. И, конечно, вам нужно тестировать, тестировать, тестировать, потому что при внесении этих изменений вручную легко ошибиться. Когда все доступы к классу Бога исчезли, вы можете, наконец, удалить его. Это звучит великолепно в теории, но это занимает много времени, если вы сталкиваетесь с тысячами модулей компиляции, и вы должны заставить членов команды прекратить добавлять доступ к интерфейсу Бога, пока вы делаете это. Однако можно применить автоматизированные инструменты рефакторинга для реализации этого; с помощью такого инструмента вы указываете раздел на инструмент, а затем надежно изменяете кодовую базу. Наша DMS может реализовать этот Рефакторинг C++ God Class и использовалась для внесения таких изменений в системы с 3000 единицами компиляции.

Другие вопросы по тегам