Информационный сайт

 

Реклама
bulletinsite.net -> Книги на сайте -> Программисту -> Бек К. -> "Экстремальное программирование: разработка через тестирование " -> 62

Экстремальное программирование: разработка через тестирование - Бек К.

Бек К. Экстремальное программирование: разработка через тестирование — СПб.: Питер, 2003. — 224 c.
ISBN 5-8046-0051-6
Скачать (прямая ссылка): bek-k..pdf
Предыдущая << 1 .. 56 57 58 59 60 61 < 62 > 63 64 65 66 67 68 .. 81 >> Следующая


}

Однако подобный корявый код имеет тенденцию распространяться по всей программе. Если для определения разницы между окружностями (circle) и не окружностями вы будете использовать условный оператор хотя бы в одном месте вашего кода, с большой долей уверенности можно сказать, что позднее подобный оператор придется добавлять также и в другом месте кода, затем в третьем и т. д.

Вторая по важности задача TDD — удаление дублирования, поэтому вы должны подавить угрозу распространения явных условных операторов в зародыше. Если вы видите, что одно и то же условие проверяется в двух разных местах вашего кода, значит, настало время выполнить базовое объектно-ориентированное преобразование: PluggableObject (Встраиваемый объект).

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

SelectionTool

Figure selected:

public void mouseDownO {

selected= findFigureO:

if (selected !» null)

select(selected);

}

public void mouseMoveO { if (selected != null)

move(selected): else

mqveSelecti onRectangl e();

}

public void mouseupO { if (selected == null) selectAllO:

}

В глаза бросаются три похожих условных оператора (я же говорил вам, что они плодятся, как мухи). Что делать, чтобы избавиться от них? Создаем встраиваемый объект, SelectionMode, обладающий двумя реализациями: SingleSelection и MultipleSelection.

SelectionTool

SelectionMode mode: public void mouseDownO {

selected= findFigureO;

if (selected != null)

mode= SingleSelection(selected);

else

mode= MultipleSelection();

}

public void mouseMoveO { mode. mouseMoveO:

}

public void mouseUpO { mode.mouseUpO:

}

В языках с явными интерфейсами вы обязаны реализовать интерфейс с двумя (или больше) встраиваемыми объектами.

Pluggable Selector1 (Встраиваемый переключатель)

Как обеспечить отличающееся поведение для разных экземпляров одного и того же класса? Сохраните имя метода в переменной и динамически обращайтесь к этому методу.

Подробнее об этом паттерне рассказывается в книге Beck, К. 1997. The Smalltalk Best Practice Patterns, с 70-73. Englewood-Cliffs, NJ: Prentice-Hall. Ссылаться на свои собственные работы — это не самая лучшая идея, однако, как говорил философ Филлис Диллер (Phyllis Diller): «Конечно же, я смеюсь над собственными шутками, просто я не доверяю никому, кроме себя».

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

abstract class Report { abstract void printO:

}

class HTMLReport extends Report { void printO { ... }

}

class XMLReport extends Report { void printO { ... }

}

Альтернативное решение: создать единственный класс с оператором switch. В зависимости от значения поля происходит обращение к разным методам. Однако в этом случае имя метода упоминается в трех местах:

• при создании экземпляра;

• в операторе switch;

• в самом методе.

abstract class Report { String printMessage;

Report(String printMessage) { this.printMessage= printMessage;

}

void printO {

switch (printMessage) { case "printHTML" : printHTMLO; break; case "printXML" : printXMLO: break:

}

}:

void printHTMLO {

, }

void printXMLO { }

'}

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

Паттерн Pluggable Selector (Встраиваемый переключатель) предлагает динамически обращаться к методу с использованием Reflection API:

void printO {

Method runMethod= getClassO .getMethod(printMessage. null):

runMethod.invoke(this. new Class[0]):

}

По-прежнему существует весьма неприятная зависимость между создателями отчетов и именами методов печати, однако, по крайней мере, мы избавились от оператора switch.

Естественно, этим паттерном не следует злоупотреблять. Самая большая связанная с ним проблема состоит в отслеживании вызываемого кода. Используйте встраиваемый переключатель только в случае, когда вы оказались в стандартной ситуации: каждый из подклассов обладает всего одним методом, и у вас есть желание сделать этот код более чистым.
Предыдущая << 1 .. 56 57 58 59 60 61 < 62 > 63 64 65 66 67 68 .. 81 >> Следующая
Реклама
Авторские права © 2009 AdsNet. Все права защищены.
Rambler's Top100