Реализация
В основном следуйте условностям кодирования от Sun-а. Они доступны с
(код же в этой книге следует им настолько, насколько это возможно). Эти принципы используются для большого числа программ и большим числом программистов. Если же Вы будете упорно использовать свой собственный стиль написания, то Вы доставите немало трудностей читателю ваших исходных кодов. Но все равно, тот стиль кодирования, который Вы предпочитаете должен соблюдаться на протяжении всего проекта. А вот здесь раздается бесплатная утилита преобразующая код Java: .
Независимо от того, какой стиль кодирования Вы используете, стиль исходного кода будет различаться в вашей команде или целиком в вашей компании. Это означает, что следует приводить стиль написания к некоему общему стилю, что в конечном результате позволит быстрее понимать написанное и сосредоточиваться на там, что этим кодом описано, а не на том, что же там все-таки написано. Следуйте стандартным правилам капитализации (изменения регистра). Капитализируйте первые буквы имен классов. Первые буквы полей, методов и объектов должны начинаться с маленькой буквы. Все идентификаторы должны содержать все слова вместе с большими буквами в начале каждого из слов. К примеру:
ThisIsAClassName
thisIsAMethodOrFieldName
Капитализируйте все буквы static final примитивов, который были проинициализованы в константы при их определении. Это будет означать, что они константы времени компиляции.
Пакеты - особый случай, они содержат все маленькие буквы, даже у внутренних слов. Расширение домена (com, org, net, edu и т.д.) должны быть так же в нижнем регистре. (Этим различаются Java 1.1 и Java 2.)
Не создавайте своих собственных, оформленных частных членов данных. Часто это выражается в виде висячих строк и символов. Яркий пример отвратительного именования - венгерская нотация, где Вы должны добавлять дополнительные символы, индицирующие тип данных, расположение и т.д., как если бы Вы писали на языке ассемблера и компилятор без этих ухищрений не справится со своей задачей. Такая нотация сбивает с толку, ее трудно читать, трудно ее соответственно писать и обслуживать. Пусть имена классов и пакетов послужат для вас примером. Следуйте каноническим формам при создании классов для основного использования. Включайте в него определения для equals( ), hashCode( ), toString( ), clone( ) (реализуйте Cloneable) и реализуйте Comparable и Serializable. Используйте JavaBean-овые "get", "set" и "is" соглашения об именовании для методов, которые читают и изменяют поля private, даже если Вы думаете, что этому компоненту не жить долго. Это не только позволит использовать этот класс как Bean, это так де и стандартный путь именования такого рода методов, что несомненно же позволит читателю более легко разобраться в исходном коде. Рассмотрите возможность поместить в каждый из классов, который Вы создаете метод static public test( ), который позволяет тестировать ваш класс. Вам не нужно удалять этот тестовый код из класса в проекте, но а когда Вы что-то измените, то можно с легкостью его протестировать. Этот же код может служить так же и примером по использованию вашего класса. Иногда вам требуется наследовать, что бы получить доступ к защищенным элементам базового класса. Это может привести к необходимости восприятия множественных базовых типов. Если же вам не нужно приводить к базовому типу, тогда сперва создайте новый дочерний класс для доступа к закрытым областям родительского класса. Затем сделайте этот новый класс элементом внутри любого другого класса, которому требуется использовать эти данные, прежде чем наследовать. Избегайте использования final методов в целях эффективности. Используйте final только если программа работает не так быстро как хотелось бы, а ваш профайлер показывает, что именно в этом месте и есть то самое бутылочное горлышко. Если два класса взаимосвязаны между собой функционально (контейнерно или итерационно), то попытайтесь сделать один из них внутренним классом другого. При этом будет не только предано специальное значение связи этих двух классов, но и появится возможность повторного использования класса внутри отдельного пакета вложением его в другой класс. Контейнерная библиотека Java-ы осуществляет такую процедуру определением внутреннего класса Iterator внутри каждого контейнерного класса, тем самым предоставляя контейнеры с общим интерфейсом. Другая причина использования внутреннего класса - частная реализация. При этом, внутренний класс скрывается от других классов и пространство имен при этом не засоряется. Всегда, когда Вы решаете, что существующий класс чересчур активно работает с другим, то использование внутреннего класса позволит увеличить производительность программы и кодирования. Использование внутренних классов не разъединит связанные классы, но сделает эту связь более ясной и простой. Не станьте добычей преждевременной оптимизации. Этот путь сравни сумасшествию. В частности, не беспокойтесь о написании (или не написании) нативных методов, создания некоторых методов с модификатором final или настройкой кода для создания эффективной системы. Ваша основная задача - реализовать проект, с наибольшей эффективностью дизайна. Сохраняйте контекст таким маленьким, как только это возможно, поскольку от этого зависит не только видимость, но и время жизни объектов. При этом уменьшается шанс использовать объект не в том контексте, а так же шанс на скрытие трудно уловимых ошибок. К примеру, представьте, что у вас есть контейнер и кусочек кода, проходящего сквозь него. Если Вы скопируете этот код для использования с другим контейнером, то вполне вероятно, что так же скопируется и кусочек старого контейнера. Или по другому может случить так, что ваш старый контейнер будет вне контекста во время компиляции. Используйте контейнеры в стандартных библиотеках Java. Становясь более профессиональным с использованием контейнеров, Вы еще к тому же значительно повысите вашу производительность. Предпочитайте ArrayList для последовательностей, HashSet для наборов, HashMap для ассоциативных массивов, а LinkedList для стеков (а не Stack) и очередей. Для программы, которая должна быть "крепкой", каждый их компонентов должен быть "крепким". Используйте все инструменты представляемые Java: управление доступом, исключения, проверка типов и т.д. для каждого класса, который Вы создаете. При этом вы сможете перейти на следующий уровень абстракции при создании вашей системы. Предпочтите ошибки времени компиляции ошибкам времени выполнения. Попытайтесь обработать все ошибки по максимуму. Обрабатывайте ошибки на месте возникновения исключения. Ловите исключения в наиближайшем хендлере, который может предоставить вам наибольшую информацию. Делайте все, что можете с исключениями на этом уровне, если же это не решает проблему, то передавайте обработку исключения дальше. Остерегайтесь длинного описания методов. Методы должны быть кратки, а функциональный модуль описывать и реализовать дискретную часть интерфейса класса. Длинный и сложный метод труден для понимания и вызывает большие расходы при выполнении, и кроме этого он пытается сделать слишком много для одного метода. Если Вы найдете такой метод, то это означает, что как минимум он должен быть разбит на несколько отдельных методов. Так же можно предложить создать и новый класс для этих методов. Маленькие же методы еще и заставляют вас их чаще повторно использовать. (Иногда методы должны быть большими, но при этом они все еще должны выполнять одну вещь.) Сохраняйте все как можно более частным образом (private). Как только вы извещаете об аспектах вашей библиотеки(метода, класса, поля), то Вы уже не сможете взять эти слова обратно. Если Вы сделали это, то Вы должны передать кому-то ваш существующий код, для дальнейшего его развития. Если же вы извещаете только о том, что необходимо, то Вы после этого можете изменять не заявленные части практически как хотите. При этом, реализация изменений окажет незначительные потрясения и изменения на дочерние классы. Ограничение видимости играет большую роль при работе с потоками, только private поля могут быть защищены против несинхронного использования. Используйте комментарии не стесняясь, а так же используйте синтаксис самодокументации javadoc. Но все равно, комментарии должны добавлять истинный смысл к коду, код с комментариями должен пониматься с легкостью, а не наоборот, когда комментарии только раздражают. Заметьте, что обычно названия классов и методов в Java уменьшают необходимость в комментариях. Избегайте использования "магических чисел", которые жестко зашиты в код. Поскольку они будут вашим ночным кошмаром, если вам потребуется однажды изменить, например, 100 значений или целый массив. Вместо этого, создавайте константы с описаниями и используйте их в своей программе. При этом вашу программу будет легче понять и опять же легче в последствии поддерживать. Когда создаете конструкторы, не забывайте об исключениях. В лучшем случае, конструктор не должен ничего делать такого, что могло бы вызвать исключение. Следующий по лучшести способ, это когда класс должен создаваться путем наследования от "крепкого" класса, так что вам не нужна будет очистка если все таки произойдет исключение. В противном случае, Вы должны производить очистку в выражении finally. Если же конструктор должен провалиться, то он должен сгенерировать исключение, иначе вызывающий его объект так и будет думать, что он создался нормально. Если ваш класс требует очистки, то поместите ваш код очистки в один, хорошо названный метод, с именем на подобии cleanup( ), которое понятно объясняет его назначение. В дополнение, поместите boolean флаг в класс, для индицирования, когда объект был правильно очищен, по этому флагу finalize( ) может проверять правильность очистки (смотри ). Ответственность finalize( ) может быть проверена только на "смертельные условия". (Смотри .) В специальных случаях, он может освобождать память, которая может быть не освобождена сборщиком мусора. Поскольку сборщик мусора может так и не вызваться для вашего проекта, то Вы не можете осуществлять требуемую очистку используя finalize( ). Для этого следует создать свой собственный метод очистки. В методе finalize( ) для класса, проверяйте, был ли данный объект правильно очищен и вызывайте исключение от RuntimeException, если это не так, что бы тем самым просигнализировать программисту об ошибке. До того, как реализовать данную схему, проверьте, работает ли на вашей системе finalize( ). (Вам может понадобиться вызвать System.gc( ), что бы вызвать такое поведение.) Если объект должен быть очищен (не сборщиком мусора) в частном случае, то используйте следующую технику: инициализируйте объект и если инициализация прошла успешно, то незамедлительно войдите в блок try с выражением finally для очистки. Когда Вы переопределяете finalize( ) во время наследования, не забывайте вызывать super.finalize( ). (Это не важно, если Object прямой родитель вашего класса.) Вы должны вызывать super.finalize( ) как завершающую часть вашего переопределения finalize( ) а не раньше, что бы быть уверенным, что объекты базового класса все еще валидны. Когда Вы создаете контейнеры фиксированного размера для объектов, то передавайте их как массивы если Вы возвращаете эти контейнеры из методов. При этом у вас будет возможность осуществлять проверку типов времени компиляции, а получатель массива может не заботиться о приведении к базовому типу. Заметьте, что базовый класс контейнерной библиотеки java.util.Collection, содержит целых два метода toArray( ). Выбирайте интерфейсы перед абстрактными классами. Если Вы знаете, что что-то собирается стать базовым классом, вам бы следовало сперва сделать его как interface, а только если Вы решаетесь включить в него определения методов и переменных, то сделайте его abstract классом. Interface декларирует, что клиент должен делать, а класс концентрирует внимание на деталях реализации. Внутри конструкторов делайте только то, что действительно нужно для инициализации объекта. Активно препятствуйте попыткам вызова других методов (исключая final), поскольку эти методы могут быть переопределены кем угодно и могут совершать неожиданные действия во время создания. (Смотри .) Маленькие, простые конструкторы намного более хороши для обработки исключений или если возникают ошибки. Что бы не набраться большого опыта по срыву проектов, убедитесь, что в classpath существует только по одному экземпляру распакованного класса (уникального). В противном случае, компилятор может найти не нужный класс с таким же именем первее нужного и сообщить при этом об ошибке. Если Вы думаете, что у вас проблемы с classpath, попытайтесь поискать классы с одинаковыми именами с начала вашей записи classpath. В идеале, лучше хранить все ваши классы в пакетах. Берегитесь случайной перегрузки. Если Вы решились переопределить метод базового класса, но при это Вы сделали небольшую ошибочку, то вам, лучше прервать редактирование нового метода и начать сначала. Поскольку при этом ошибки может и не быть, а вот метод работать правильно уже не будет. Берегитесь преждевременной оптимизации. Сначала заставьте его работать, затем сделайте его быстрым, но только, если Вы должны сделать это, и только если этот участок кода действительно бутылочное горлышко, тормозящее всю систему. В противном случае, если Вы не знаете, что тормозит вашу систему, то используйте профайлер, для поиска этого пресловутого бутылочного горлышка. К тому же минусом оптимизации будет и то, что оптимизированный код будет труднее читать и обрабатывать. Запомните, что код больше раз читается, нежели пишется. Читая проектировка создает легко понимаемые программы, но все таки без комментариев и разъяснения деталей они будут не очень понятны. А проектировка и комментарии к ней с разъяснениями помогут вашим последователям, кто придет после вас.
[85] Разъяснено мне Andrew Koenig.
[ ] [ ] [ ] [ ] [ ]
Содержание раздела