Thinking in Java, 2nd edition, Revision
11
©2000 by Bruce Eckel
C: Руководящие принципы программирования на Java
Это приложение содержит предложения призванные помочь вам в осуществлении
низкоуровневой проектировки программных продуктов и последующего написания кода.
В действительности же, это только принципы, но не правила. Идея заключается
в использовании заложенных в них идей и при этом следует не забывать об исключениях
из правил, когда нужно отбросить или изменить какое-то правило.
Проектировка
- Элегантность окупается всегда. В этой короткой фразе заключается
глубокий смысл. Создание элегантного решения требует большего времени, но
в последствии адаптировать его для других задач или исправить ошибки будет
намного проще и быстрее, в противном случае, могут понадобиться дни, недели
или месяцы усилий прежде того, как Вы увидите результаты (даже если никто
их и не оценит). Элегантность не только позволяет вам проще создавать или
отлаживать программу, но и проще ее понять и обслуживать в дальнейшем, что
очень положительно сказывается на финансах. Этот способ требует некоторого
опыта для понимания, потому что он не может быть применен для небольшого кусочка
кода. И ограничьте различного рода "подгонятелей", они только замедляют
работу (в последствии).
- Сначала пускай он работает, а затем сделаем его быстро работающим.
Этот принцип верен, если Вы уверены, что этот кусочек кода действительно важен
и именно он будет бутылочным горлышком в вашей системе. Не делайте сразу его
полностью оптимизированным. Дайте системе сначала наивозможно простую модель.
Затем, если нужные участки не достаточно быстры, то оптимизируйте их. Затем
вы уже всегда будете понимать, действительно ли это узкое место или все-таки
нет. Сохраните ваше время для более важных дел.
- Помни принцип "Разделяй и властвуй". Если разрешаемая проблема
слишком запутанна, то попытайтесь представить, что эта основная операция должна
быть составлена из "магических" кусочков, которые уже содержат сложные
части. Эти кусочки - объекты, напишите код, использующий эти объекты, а сложные
части инкапсулируйте в другие объекты и т.д.
- Отделяй создателя класса от пользователя класса (клиентское программирование).
Пользователь класса - простой потребитель, он не должен знать что именно и
как происходит внутри ваших классов. Создатель класса должны быть экспертом
в создании и проектировки классов, поэтому получаемый класс должен быть максимально
прост в использовании. Библиотеки использовать легко, если они "прозрачны"
и ясны.
- Когда Вы создаете класс, старайтесь дать ему имя такое, что бы не нужны
были комментарии. Ваша задача сделать интерфейс клиентского программиста
концептуально простым. Для этого используйте перегрузку методов, когда нужно
и легкий в использовании интерфейс.
- Ваша модель системы должна производить по минимуму классов, интерфейсов
и связей с другими классами, в частности с базовыми. Если ваш проект создает
больше чем нужно, спросите себя, нужны ли все эти методы, интерфейсы и связи
во время работы программы? Если нет, то их поддержка вам еще встанет боком.
Члены групповой разработки стараются избавляться от ненужных частей проекта,
что существенно сказывается на их производительности.
- Автоматизируй все! Пишите тестовый код в первую очередь (до
того, как напишите сам класс) и сохраните его вместе с классом. Автоматизируйте
запуск ваших тестов посредством makefile или похожей приблуды. Тогда любые
изменения в коде могут быть автоматически проверены запуском теста, а Вы при
этом немедленно получите все ваши ошибки. Поскольку Вы знаете о том, что ваши
тесты верны и безопасны (ведь так?), то Вы можете больше экспериментировать
в поиске правильного решения поставленных задач. Вспомните, что наибольшим
повышением производительности в языках программирования стал встроенный тест
по проверке типов, а так же по обработке исключений и т.д. Вы должны отойти
от создания трудоемкой системы к для созданию тестов, которые будут проверять
вашу программу на спецификации.
- Пишите сперва тестовый код, до того, как Вы напишите ваш класс, в порядке
проверки правильности проектировки. Если Вы не можете написать тестовый
код, то Вы и не знаете как будет выглядеть ваш класс в действительности. В
дополнение, написание тестового кода часто смывает дополнительные возможности
или принуждает внести необходимые возможности в ваш класс, а так же пересмотреть
модель вашего проекта. Тесты так же служат кодом примеров, показывающим, как
нужно использовать ваш класс.
- Все проблемы проектировки программного обеспечения могут быть выявлены
введением дополнительного уровня абстрактного "отрешения".
Это фундаментальное правило программных разработок[85]
является базой абстракции, основной возможности объектно-ориентированного
программирования.
- "Отрешение" должно иметь смысл (в сочетании с принципом
9). Это означает, что все что "простое" должно быть отдельно (отдельный
код в отдельном методе). Если же Вы добавите еще один уровень абстракции,
то это будет уже плохо.
- Создавайте классы настолько атомарными, на сколько это возможно.
Давайте каждому классу простое, понятное предназначение. Если ваши классы
или ваша система проектирования растет слишком сложной, разделите сложные
классы на несколько простых. Наиболее понятным индикатором можно считать абсолютный
размер: если класс велик, то есть шанс его разделить на несколько маленьких.
Ключи для предположения по перепроектировке класса:
1) Запутанные операторы: подумайте о полиморфизме.
2) Большое число методов, которые обрабатывают различные типы или операции: подумайте о нескольких классах.
3) Большое число элементов переменных, которые относятся к различным характеристикам:
подумайте о нескольких классах.
- Следите за длинными списками аргументов. При этом вызовы, запись,
чтение или обработка методов значительно затруднены. Вместо этого попробуйте
переместить метод в класс, где его наиболее часто употребляют или передавайте
ему объекты, как аргументы.
- Не повторяйтесь. Если некий кусочек кода требуется в многих методах
дочерних классов, то поместите его в один метод базового класса, а затем вызывайте
его из дочернего. Это не только позволит сохранить место, но и позволит с
легкостью вносить изменения. Иногда изучение этого общего кода приносит дополнительную
функциональность вашему интерфейсу.
- Следите за выражениями switch и цепочками if-else.
Это всего лишь индикатор проверки кодирования, что означает, что Вы выбираете,
какой код будет выполнен на основании некой информации (точный тип может быть
не известен первоначально). Вы должны заменять этот код посредством наследования
и полиморфизма; вызовы полиморфных методов выполняют за вас всю работу по
проверке типов, что в результате позволяет иметь более гибкую систему.
- С точки зрения проектировки, найдите и отделите те вещи, которые могут
изменяться от тех, которые всегда постоянны. Это означает, что нужно в
системе найти элементы, которые Вы можете изменить без принудительного редизайна,
затем инкапсулируйте их в отдельные классы. Вы можете значительно больше узнать
об этом в книге Thinking in Patterns with Java, доступной с www.BruceEckel.com.
- Не расширяйте фундаментальную функциональность посредством подклассов.
Если элемент интерфейса для класса важен, то он должен быть в базовом классе,
а не добавлен в процессе наследования. Если же Вы добавляете методы во время
наследования, то стоит подумать о перепроектировке.
- Меньше - больше. Начинайте с минимума интерфейса класса, как можно
меньшего, что бы только хватало решить поставленную задачу, не пытайтесь предугадать
все варианты, как может быть использован ваш класс. Как только ваш класс будет
использован, то здесь уже можно посмотреть и расширять его интерфейс. Но все
равно, как только Вы "выпустите" класс, то уже будет невозможно
раширять его интерфейс, без изменения его кода. Если вам нужно расширить интерфейс
существующих методов, добавлением новых аргументов, создайте перегруженный
метод с новыми аргументами.
- "Прочтите" ваш класс в слух, что бы убедиться, что он логичен.
Убедитесь, что отношения между базовым классом и дочерним классом есть "это
- есть" ("is-a"), а у элементов класса "имеет это"
("has-a").
- Во время принятия решения по использованию наследования или композиции,
спросите себя, а нужно ли мне использовать приведение к базовому типу?
Если нет, то предпочтите композицию наследованию. При этом отпадет необходимость
в множестве базовых типов. Если же Вы наследуете, то пользователи могут не
без оснований думать, что можно произвести приведение к базовому типу.
- Используйте элементы данных для разнообразия в значениях, а переопределение
методов для разнообразия в поведении. Это означает, что если Вы найдете
класс, который использует значения переменных в месте с методами, для того,
что бы изменять поведение в зависимости от значений этих переменных, то следует,
скорее всего, перепроектировать этот класс. Нужно выразить различие в поведении
в подклассы и переопределенные методы.
- Следите за перегрузкой. Метод не должен выполняться на основе аргумента,
вместо этого нужно создать два или более перегруженных методов.
- Используйте иерархию исключений, желательно наследовать от специального
класса в стандартной иерархии исключений Java. Если кто-то обрабатывает исключения,
то он может обрабатывать только определенные типы исключений, следующие от
этого базового класса. Если Вы добавляете новое дочернее исключение, то существующий
клиентский код его все равно обработает, основываясь на базовом типе.
- Иногда простая агрегация выполняют всю работу. "Система комфорта
пассажира" на авиалиниях состоит из различных, отсоединенных друг от
друга частей: сиденья, кондиционеры воздуха, видео и т.д., а теперь представьте,
что вам нужно создать несколько таких систем в самолете. Вы сделаете частные
(новые) элементы и создадите новый интерфейс? Нет, в этом случае, компоненты
также являются частью публичного интерфейса, поэтому Вы должны просто создать
публичные элементы-объекты. Эти объекты имеют свою собственную реализацию,
но при этом они так же безопасны. Знайте, что простая агрегация не то решение,
которое может часто применяться, но при его использовании все счастливы.
- Примите во внимание клиентского программиста и того, кто будет обслуживать
ваш код. Проектируйте ваш класс настолько ясно, насколько это возможно
для использования. Предвидьте те изменения, которые могут с ним произойти
и спроектируйте ваш класс так, что бы привнести их было в него просто.
- Остерегайтесь синдрома гигантских объектов. Этот синдром - частое
несчастье процедурных программистов, которые только начинают программировать
в ООП, и кто еще не закончил писать процедурные программы и обычно помещает
в своей объектной программе несколько больших объектов и все.
- Если Вы должны сделать что-то ужасное, то меньшей мере сделайте это внутри
класса.
- Если вам нужно сделать что-то непереносимое, то создайте абстракцию и
локализуйте ее в отдельном классе. Это уже более высокий уровень абстрагирования
непереносимых элементов, которые будут распространяться с вашей системой.
(Эта идиома материализована в шаблоне Bridge).
- Объект должен не просто содержать данные. Они должны так же иметь
и определенные принципы поведения. (Иногда, чистые объекты данных подходят,
но только когда они используются для хранения или передачи группы элементов.)
- Сперва используйте композицию, когда создаете новый класс от уже существующего.
Вы должны использовать наследование только, если это требование вашего дизайна.
Если Вы используете наследование, где должна быть использована композиция,
то тогда ваш дизайн без нужды запутанный.
- Используйте наследование и переопределение методов для выражения различий
в поведении, а поля для выражения различий в положении. Крайним случаем
того, чего не нужно делать - наследование различных классов для отображения
цвета, вместо использования поля цвета.
- Остерегайтесь конфликтов. Два семантически различных объектов могут
иметь идентичные возможности по действиям или по ответственности, при этом
возникает искушение попытаться создать один подкласс от этих классов посредством
наследования. Отсюда и возникает конфликт, однако в этом случае нет необходимости
оправдывающей создание связи дочернего класса с суперклассом. Поэтому лучшим
решением будет создать главный базовый класс, который реализует интерфейс
для обоих дочерних классов, при этом потребуется немного больше места, но
у вас останутся все преимущества наследования.
- Остерегайтесь ограничений наследования. В ясном дизайне новые возможности
добавляются в наследуемые объекты. Подозрительный дизайн удаляет старые возможности
во время наследования без добавления новых. Но правила могут нарушаться, и
если Вы работаете из старой библиотеки класса, то было бы лучше ограничить
существующий класс в его подклассе так что бы была возможность переработать
иерархию наследования, что бы ваш класс был там, где ему положено быть - над
старым классом.
- Используйте шаблоны проектировки, что бы исключить "голую функциональность".
Это означает, что если вам нужен только один созданный объект вашего класса,
то добавьте комментарий "Создавайте только один". Оберните его в
одноэлементное множество (синглтон). Если же у вас имеется много грязного
кода в вашей главной программе, которая создает ваши объекты, то, обратитесь
к шаблонам создания, например, к методам предприятия, с помощью которых Вы
и можете реализовать это создание. Исключение "голой функциональности"
не только сделает ваш код более легким для понимания и поддержки, оно так
же сделает его более пуленепробиваемым против "доброжелателей" пришедших
после вас.
- Остерегайтесь аналитического паралитизма. Запомните, что Вы должны
обычно продвигаться в перед в проекте до того, как Вы узнаете все о нем, а
лучшим способом при этом будет узнавать то, что Вы не знаете до того, как
Вы к этому приступите. Вы не будете знать решения до того, как Вы получите
его. Java сделана по принципу файрволов (брендмауеров), дайте им поработать
в ваших интересах. Ваши ошибки в классе или наборе классов не разрушат целостность
всей системы.
- Когда Вы думаете, что Вы хорошо проанализировали систему, создали отличный
проект или его реализацию, то критично оцените (проанализируйте ее сквозным
методом) всю систему целиком. Покажите систему какому - либо стороннему
лицу, кто не участвовал в разработке или консультациях. Взгляд на систему
парой "новых" глаз зачастую помогает выявить недостатки и недоделки.
Реализация
- В основном следуйте условностям кодирования от Sun-а. Они доступны с
java.sun.com/docs/codeconv/index.html
(код же в этой книге следует им настолько, насколько это возможно). Эти принципы
используются для большого числа программ и большим числом программистов. Если
же Вы будете упорно использовать свой собственный стиль написания, то Вы доставите
немало трудностей читателю ваших исходных кодов. Но все равно, тот стиль кодирования,
который Вы предпочитаете должен соблюдаться на протяжении всего проекта. А
вот здесь раздается бесплатная утилита преобразующая код Java: home.wtal.de/software-solutions/jindent.
- Независимо от того, какой стиль кодирования Вы используете, стиль исходного
кода будет различаться в вашей команде или целиком в вашей компании. Это
означает, что следует приводить стиль написания к некоему общему стилю, что
в конечном результате позволит быстрее понимать написанное и сосредоточиваться
на там, что этим кодом описано, а не на том, что же там все-таки написано.
- Следуйте стандартным правилам капитализации (изменения регистра). Капитализируйте первые буквы имен классов.
Первые буквы полей, методов и объектов должны начинаться с маленькой буквы. Все идентификаторы должны содержать все слова вместе с большими буквами в начале каждого из слов. К примеру:
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( ) может проверять правильность очистки (смотри главу
4).
- Ответственность finalize( ) может быть проверена только на
"смертельные условия". (Смотри главу
4.) В специальных случаях, он может освобождать память, которая может
быть не освобождена сборщиком мусора. Поскольку сборщик мусора может так и
не вызваться для вашего проекта, то Вы не можете осуществлять требуемую очистку
используя finalize( ). Для этого следует создать свой собственный
метод очистки. В методе finalize( ) для класса, проверяйте, был
ли данный объект правильно очищен и вызывайте исключение от RuntimeException,
если это не так, что бы тем самым просигнализировать программисту об ошибке.
До того, как реализовать данную схему, проверьте, работает ли на вашей системе
finalize( ). (Вам может понадобиться вызвать System.gc( ),
что бы вызвать такое поведение.)
- Если объект должен быть очищен (не сборщиком мусора) в частном случае,
то используйте следующую технику: инициализируйте объект и если инициализация
прошла успешно, то незамедлительно войдите в блок try с выражением
finally для очистки.
- Когда Вы переопределяете finalize( ) во время наследования,
не забывайте вызывать super.finalize( ). (Это не важно, если
Object прямой родитель вашего класса.) Вы должны вызывать super.finalize( )
как завершающую часть вашего переопределения finalize( ) а не
раньше, что бы быть уверенным, что объекты базового класса все еще валидны.
- Когда Вы создаете контейнеры фиксированного размера для объектов, то
передавайте их как массивы если Вы возвращаете эти контейнеры из методов.
При этом у вас будет возможность осуществлять проверку типов времени компиляции,
а получатель массива может не заботиться о приведении к базовому типу. Заметьте,
что базовый класс контейнерной библиотеки java.util.Collection, содержит
целых два метода toArray( ).
- Выбирайте интерфейсы перед абстрактными классами. Если Вы знаете,
что что-то собирается стать базовым классом, вам бы следовало сперва сделать
его как interface, а только если Вы решаетесь включить в него определения
методов и переменных, то сделайте его abstract классом. Interface
декларирует, что клиент должен делать, а класс концентрирует внимание
на деталях реализации.
- Внутри конструкторов делайте только то, что действительно нужно для инициализации
объекта. Активно препятствуйте попыткам вызова других методов (исключая
final), поскольку эти методы могут быть переопределены кем угодно и
могут совершать неожиданные действия во время создания. (Смотри главу
7.) Маленькие, простые конструкторы намного более хороши для обработки
исключений или если возникают ошибки.
- Что бы не набраться большого опыта по срыву проектов, убедитесь, что
в classpath существует только по одному экземпляру распакованного класса (уникального).
В противном случае, компилятор может найти не нужный класс с таким же именем
первее нужного и сообщить при этом об ошибке. Если Вы думаете, что у вас проблемы
с classpath, попытайтесь поискать классы с одинаковыми именами с начала вашей
записи classpath. В идеале, лучше хранить все ваши классы в пакетах.
- Берегитесь случайной перегрузки. Если Вы решились переопределить
метод базового класса, но при это Вы сделали небольшую ошибочку, то вам, лучше
прервать редактирование нового метода и начать сначала. Поскольку при этом
ошибки может и не быть, а вот метод работать правильно уже не будет.
- Берегитесь преждевременной оптимизации. Сначала заставьте его работать,
затем сделайте его быстрым, но только, если Вы должны сделать это, и только
если этот участок кода действительно бутылочное горлышко, тормозящее всю систему.
В противном случае, если Вы не знаете, что тормозит вашу систему, то используйте
профайлер, для поиска этого пресловутого бутылочного горлышка. К тому же минусом
оптимизации будет и то, что оптимизированный код будет труднее читать и обрабатывать.
- Запомните, что код больше раз читается, нежели пишется. Читая проектировка
создает легко понимаемые программы, но все таки без комментариев и разъяснения
деталей они будут не очень понятны. А проектировка и комментарии к ней с разъяснениями
помогут вашим последователям, кто придет после вас.
[85] Разъяснено мне Andrew Koenig.