java.io.Externalizable
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
}
Добавление параметра-накопителя зачастую является последствием использования шаблона «Компоновщик» (Composite). В начале разработки JUnit не было необходимости накапливать результаты выполнения нескольких тестов в объекте TestResult до тех пор, пока в инфраструктуру не была добавлена возможность создания и запуска нескольких тестов.
Необходимость использования параметра-накопителя возникает в ситуации, когда возрастает сложность объекта, получаемого в результате комплексной операции. Например, представьте, что нам необходимо реализовать вывод объекта Expression на экран в виде строки символов. Если обычная, не структурированная строка – это все, что нам нужно, значит, конкатенации будет вполне достаточно:
testSumPrinting() {
Sum sum = new Sum(Money.dollar(5), Money.franc(7));
assertEquals("5 USD + 7 CHF", sum.toString());
}
String toString() {
return augend + " + " + addend;
}
Однако если мы хотим отобразить объект Expression в виде древовидной структуры, код может выглядеть следующим образом:
testSumPrinting() {
Sum sum = new Sum(Money.dollar(5), Money.franc(7));
assertEquals("+\n\t5 USD\n\t7 CHF", sum.toString());
}
В этом случае придется воспользоваться параметром-накопителем:
String toString() {
IndentingStream writer = new IndentingStream();
toString(writer);
return writer.contents();
}
void toString(IndentingWriter writer) {
writer.println("+");
writer.indent();
augend.toString(writer);
writer.println();
addend.toString(writer);
writer.exdent();
}
Одиночка (Singleton)
Как можно реализовать глобальную переменную в языке, в котором не поддерживаются глобальные переменные? Не следует этим заниматься. Ваша программа скажет вам большое спасибо, если вместо этого вы еще раз хорошенько обдумаете дизайн и откажетесь от мысли использовать глобальные переменные.
Рассматриваемые здесь шаблоны помогут изменить дизайн системы маленькими шажками.
В рамках TDD рефакторинг [27]используется интересным образом. Обычно рефакторинг не может изменить семантику программы ни при каких условиях. В рамках TDD условия семантики формулируются при помощи тестов, которые уже выполняются успешно. Таким образом, в рамках TDD мы можем, например, заменить константы переменными и с чистой совестью назвать эту процедуру рефакторингом, потому что набор успешных тестов при этом не изменился. Однако набор успешных тестов может состоять всего из одного теста. Возможно, семантика программы должна описываться большим количеством тестов. Возможно также, что некоторые из этих потенциальных тестов в результате выполнения рефакторинга перестали бы срабатывать, если бы они существовали. Однако их нет, поэтому мы о них не беспокоимся.
Отсюда следует, что на программиста, работающего в стиле TDD, возлагается важная обязанность: он должен иметь достаточное количество тестов, описывающих семантику программы. Достаточное настолько, насколько он может судить на момент завершения работы над кодом. Необходимо понимать, что рефакторинг выполняется не с учетом всех существующих тестов, а с учетом всех возможных тестов. Фраза: «Я знаю, что там была проблема, но все тесты выполнились успешно, поэтому я посчитал код завершенным и интегрировал его в систему», – не может считаться оправданием. Пишите больше тестов.
Согласование различий (Reconcile Differences)
Как можно унифицировать два схожих фрагмента кода? Постепенно делайте их все более похожими друг на друга. Унифицируйте их только в случае, если они абсолютно идентичны.
Подчас рефакторинг – это весьма нервная работа. Простые изменения в коде очевидны. Если я извлекаю метод и делаю это механически корректно, вероятность того, что поведение системы изменится, чрезвычайно мала. Однако некоторые из изменений заставляют внимательно анализировать последовательность выполнения операций и порядок модификации данных. Построив длинную цепочку умозаключений, вы приходите к выводу, что запланированное вами изменение кода, скорее всего, не приведет к изменению поведения системы. Однако любой подобный рефакторинг уменьшает количество волос на вашей голове.
Сложные изменения – это именно то, чего мы пытаемся избежать, когда придерживаемся стратегии маленьких шажков и конкретной обратной связи. Полностью избежать сложных изменений невозможно, однако можно уменьшить их влияние на остальной код.
Подобные изменения возникают на разных уровнях:
• Два цикла выглядят похоже. Если вы сделаете их идентичными, вы сможете объединить их в единый цикл.
Читать дальше
Конец ознакомительного отрывка
Купить книгу