Мы проанализируем код SerialDate от начала до конца, усовершенствуя его в ходе просмотра. Хотя ниже об этом не упоминается, после каждого вносимого изменения выполнялись все модульные тесты JCommon, включая мой доработанный модульный тест SerialDate. Итак, вы можете быть уверены в том, что вносимые изменения не нарушают работы JCommon.
Начнем со строки 1. В ней приводятся многословные комментарии с информацией о лицензии, авторских правах, авторах и истории изменений. Бесспорно, существуют некоторые юридические формальности, которые необходимо соблюдать, поэтому авторские права и лицензии должны остаться. С другой стороны, история изменений является пережитком из 1960-х годов. Сегодня у нас имеются системы управления исходным кодом, которые все это делают за нас. Историю следует удалить [C1].
Список импорта, начинающийся в строке 61, следует сократить при помощи конструкций java.text.* и java.util.* [J1].
К форматированию HTML в Javadoc (строка 67) я отношусь без восторга. Меня беспокоят исходные файлы, написанные более чем на одном языке. В этом комментарии встречаются четыре языка: Java, английский, Javadoc и HTML [G1]. При таком количестве языков трудно поддерживать порядок в коде. Например, аккуратное размещение строк 71 и 72 теряется при генерировании кода Javadoc, да и кому захочется видеть теги
, чтобы форматирование в исходном коде сохранилось в Javadoc[72].
Строка 86 содержит объявление класса. Почему этот класс называется SerialDate? Почему в нем присутствует слово «serial» — только потому, что класс объявлен производным от Serializable? Это выглядит маловероятно.
Не буду держать вас в неведении. Я знаю (или по крайней мере полагаю, что знаю), почему было использовано слово «serial». На это указывают константы SERIAL_LOWER_BOUND и SERIAL_UPPER_BOUND в строках 98 и 101. Еще более очевидная подсказка содержится в комментарии, начинающемся в строке 830. Класс назван SerialDate, потому что его реализация построена на использовании «порядкового номера» (serial number), то есть количества дней с 30 декабря 1899 года.
На мой взгляд, у такого решения два недостатка. Во-первых, термин «порядковый номер» некорректен. Кому-то это покажется пустяком, но выбранное представление представляет собой относительное смещение, а не порядковый номер. Термин «порядковый номер» скорее относится к маркировке промышленных изделий, а не к датам. Так что, на мой взгляд, название получилось не слишком содержательным [N1].
Второй недостаток более важен. Имя SerialDate подразумевает определенную реализацию. Однако класс является абстрактным и для него реализацию скорее нужно скрывать! Я считаю, что выбранное имя находится на неверном уровне абстракции [N2]. По моему мнению, класс было бы лучше назвать Date.
К сожалению, в библиотеку Java входит слишком много классов с именем Date; вероятно, это не лучший вариант. Поскольку класс скорее ориентирован на работу с сутками, я подумывал о том, чтобы назвать его Day, но и это имя часто используется в других местах. В конечном итоге я решил, что лучшим компромиссом будет имя DayDate.
В дальнейшем обсуждении будет использоваться имя DayDate. Не забывайте, что в листингах, на которые вы будете смотреть, класс по-прежнему называется SerialDate.
Я понимаю, почему DayDate наследует от Comparable и Serializable. Но почему он наследует от MonthConstants? Класс MonthConstants (листинг Б.3, с. 417) представляет собой простой набор статических констант, определяющих месяцы. Наследование от классов с константами — старый трюк, который использовался Java-программистами, чтобы избежать выражений вида MonthConstants.January, но это неудачная мысль [J2]. MonthConstants следовало бы оформить в виде перечисления.
public abstract class DayDate implements Comparable,
Serializable {
public static enum Month {
JANUARY(1),
FEBRUARY(2),
MARCH(3),
APRIL(4),
MAY(5),
JUNE(6),
JULY(7),
AUGUST(8),
SEPTEMBER(9),
OCTOBER(10),
NOVEMBER(11),
DECEMBER(12);
Month(int index) {
this.index = index;
}
public static Month make(int monthIndex) {
for (Month m : Month.values()) {
if (m.index == monthIndex)
return m;
}
throw new IllegalArgumentException("Invalid month index " + monthIndex);
}
public final int index;
}