Экстремальное программирование. Разработка через тестирование | страница 109




File

public boolean setReadOnly() {

SecurityManager security = System.getSecurityManager();

security.canWrite(path);

return fileSystem.setReadOnly(this);

}

Однажды во время выступления на конференции OOPSLA нас с Эр

ихом Гаммой (Erich Gamma) спросили, можно ли использовать «Нуль-объект» (Null Object) в рамках одного из классов JHotDraw. Я принялся рассуждать о преимуществах такой модернизации, в то время как Эрих посчитал, что для этого нам придется увеличить код на десять строк, при этом мы избавимся от одного условного оператора – преимущество сомнительно. (К тому же аудитория была весьма недовольна нашей несогласованностью.)

Шаблонный метод (Template Method)

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

В программировании существует огромное количество классических последовательностей:

• ввод – обработка – вывод;

• отправить сообщение – принять ответ;

• прочитать команду – вернуть результат.

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

Поддерживаемый любым объектно-ориентированным языком механизм наследования обеспечивает простой способ определения универсальных последовательностей. В суперклассе создается метод, целиком и полностью написанный в терминах других методов. Каждый из подклассов может реализовать эти методы так, как ему удобнее. Например, базовая последовательность выполнения теста определяется в инфраструктуре JUnit следующим образом:


TestCase

public void runBare() throws Throwable {

setUp();

try {

runTest();

}

finally {

tearDown();

}

}


Классы, производные от TestCase, могут реализовать setUp(), runTest() и tearDown() так, как им этого хочется.

При использовании шаблона «Шаблонный метод» (Template Method) возникает вопрос: надо ли создавать для подметодов реализации по умолчанию? В TestCase.runBare() все три подметода обладают реализациями по умолчанию:

• методы setUp() и tearDown() не выполняют никаких операций;

• метод runTest() динамически обнаруживает и запускает все тестовые методы, исходя из имени класса-теста.

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