В разгаре битвы я могу вдруг обнаружить, что попался в ловушку собственной гениальности. (Не буду говорить, насколько часто это происходит.) Когда это происходит, я использую «Встраивание метода» (Inline Method), чтобы разобраться в той путанице, которую я создал: «Так, этот объект обращается к этому, этот к этому… не могу понять, что же здесь происходит?» Я встраиваю несколько уровней абстракции и смотрю, что же на самом деле происходит. После этого я могу заново выделить абстракцию, использовав более удобный способ.
Выделение интерфейса (Extract Interface)
Как создать альтернативные реализации операций в языке Java? Создайте интерфейс, в котором будут содержаться общие операции.
Как
1. Напишите объявление интерфейса. Иногда в качестве имени интерфейса используется имя существующего класса. В этом случае вы должны предварительно переименовать класс.
2. Сделайте так, чтобы существующий класс реализовывал объявленный вами интерфейс.
3. Добавьте в интерфейс все обязательные методы. В случае необходимости измените режим видимости методов класса.
4. Там, где это возможно, измените объявления с класса на интерфейс.
Зачем
Иногда необходимость выделения интерфейса возникает в случае, когда вы переходите от одной реализации к другой. Например, у вас есть класс Rectangle (прямоугольник), и вы хотите создать класс Oval (овал) – в этом случае вы создаете интерфейс Shape (фигура). В подобных ситуациях подобрать имя для интерфейса, как правило, несложно. Однако иногда приходится изрядно помучиться, прежде чем обнаружится подходящая метафора.
Иногда, когда нужно выделить интерфейс, вы используете шаблон «Тестирование обработки ошибок» (Crash Test Dummy) или «Поддельный объект» (Mock Object). В этом случае подбор подходящего имени выполняется сложнее, так как в вашем распоряжении лишь один пример использования интерфейса. В подобных случаях у меня возникает соблазн наплевать на информативность и назвать интерфейс IFile, а реализующий его класс – File. Однако я приучил себя останавливаться на мгновение и размышлять о том, достаточно ли хорошо я понимаю то, над чем работаю? Возможно, интерфейс лучше назвать File, а реализующий его класс – DiskFile, так как соответствующая реализация основана на том, что данные, содержащиеся в файле, хранятся на жестком диске.
Перемещение метода (Move Method)
Как можно переместить метод в новое место, где он должен находиться? Добавьте его в класс, которому он должен принадлежать, затем обратитесь к нему.
Как
1. Скопируйте метод в буфер обмена.
2. Вставьте метод в целевой класс. Присвойте ему подобающее имя. Скомпилируйте его.
3. Если внутри метода происходит обращение к первоначальному объекту, добавьте параметр, при помощи которого методу будет передаваться этот объект. Если внутри метода происходит обращение к переменным-членам первоначального объекта, передавайте их в виде параметров. Если внутри метода переменным-членам первоначального объекта присваиваются значения, вы должны отказаться от идеи переноса метода в новый объект.
4. Замените тело первоначального метода обращением к новому методу.
Зачем
Это один из моих самых любимых шаблонов рефакторинга, выполняемых в процессе консультирования. Дело в том, что он наиболее эффективно демонстрирует неправильные предположения относительно дизайна кода. Вычисление площади – это обязанность объекта Shape (фигура):
Shape
…
int width = bounds.right() – bounds.left();
int height = bounds.bottom() – bounds.top();
int area = width * height;
…
Каждый раз, когда я вижу, что внутри метода, принадлежащего одному объекту, происходит обращение к нескольким методам другого объекта, я начинаю смотреть на код с подозрением. В данном случае я вижу, что в методе, принадлежащем объекту Shape, происходит обращение к четырем методам объекта bounds (класс Rectangle). Пришло время переместить эту часть метода в класс Rectangle:
Rectangle
public int area() {
int width = this.right() – this.left();
int height = this.bottom() – this.top();
return width * height;
}
Shape
…
int area = bounds.area();
…
Шаблон рефакторинга «Перемещение метода» (Move Method) обладает тремя важными преимуществами:
• Очень легко увидеть необходимость применения этого вида рефакторинга, при этом не требуется глубокое понимание смысла кода. Как только вы увидите два или больше сообщения, адресованные другому объекту, значит, можно смело приступать.
Читать дальше
Конец ознакомительного отрывка
Купить книгу