Как провести рефакторинг: разделить класс на два, которые общаются через интерфейс
-
04-07-2019 - |
Вопрос
Я только начинаю свой первый крупномасштабный рефакторинг, и мне нужно разделить (к сожалению, большой) класс на два, которые затем взаимодействуют только через интерфейс. (Мой Presenter оказался контроллером и должен отделить логику графического интерфейса от логики приложения). Используя C # в VisualStudio 2008 и Resharper, какой самый простой способ добиться этого? Р>
Я собираюсь попробовать а) собрать членов для нового класса и "извлечь новый класс"; б) навести порядок c) "Извлечь интерфейс" d) выследить любые ссылки на класс и преобразовать их в ссылки интерфейса
но я никогда не делал этого раньше, и удивляюсь, знает ли кто-нибудь какие-нибудь хорошие советы или ошибки, прежде чем я начну все разрывать на части ... Спасибо!
Решение
Детские шаги.
Шаг 1. Внесите небольшое изменение, используя отличный рефакторинг Resharper.
Шаг 2: Тестирование (желательно модульное тестирование), чтобы убедиться, что код все еще работает
Шаг 3. Передайте управление исходным кодом
Повторите эти 3 шага много раз.
Может быть, это не сработает, если вы выполняете одно из этих действий, " должен быть большой шаг за один раз " рефакторинга. В этом случае сделайте как можно больше мелких рефакторингов, прежде чем окунуться в большой шаг.
Другие советы
Называй меня старомодным, но лично я использую описанные тобой автоматические функции только для технических задач (таких как переименование и т. д.)
Для всех других рефакторингов, таких как извлечение интерфейсов и тому подобное, я предпочитаю делать вручную. Вы обнаружите, что вы можете сделать еще больший рефакторинг, и, как правило, код будет более чистым.
У меня есть только один важный совет - убедитесь, что вы можете вернуться к состоянию, прежде чем запускать рефакторинг, не теряя ничего. Тогда просто погрузитесь и сделайте это. Вы можете в конечном итоге остановиться и начать все заново, но бояться нечего (если вы прислушались к моему единственному совету). Вы многому научитесь, делая это.
Сначала краткий ответ, я напишу об этом в блоге, спасибо за идею!
Итак, давайте предположим, что у нас есть это:
class PresenterAndController
{
public void Control()
{
Present();
}
public void Present()
{
// present something
}
}
Во-первых, нам нужно преобразовать все прямые использования членов в косвенные, то есть определить их с помощью поля. Для этого используйте рефакторинг экстракта суперкласса для извлечения части Presenter в суперкласс:
internal class Presenter
{
public void Present()
{
// present something
}
}
class PresenterAndController : Presenter
{
public void Control()
{
Present();
}
}
Создайте поле в PresenterAndController, которое будет делегировать одно, и используйте Generate (Alt-Ins) для создания делегирующих членов. Они будут скрывать базовые методы, так как они одинаковые:
internal class Presenter
{
public void Present()
{
// present something
}
}
class PresenterAndController : Presenter
{
private Presenter myPresenter;
public void Present() // hides base method
{
myPresenter.Present();
}
public void Control()
{
Present(); // it now references method from this type
}
}
Удалите Presenter из списка наследования, и все готово для разделения классов. Теперь вы можете извлекать интерфейсы, использовать базовые типы, где это возможно, и иным образом приводить их в порядок.
Я никогда не использовал VisualStudio, но нахожу, что автоматический рефакторинг в Eclipse достаточно надежен - по крайней мере, настолько же надежен, как если бы я выполнял ту же работу.
Прежде чем сделать это, инвестируйте в контроль версий: изучите Git. Рефакторинг без SCM походит на вождение с завязанными глазами.