Эккель Брюс
Шрифт:
Чтобы эффективно использовать полиморфизм — а значит, все объектно-ориентированные приемы — в своих программах, необходимо расширить свои представления о программировании, чтобы они охватывали не только члены и сообщения отдельного класса, но и общие аспекты классов, их взаимоотношения. Хотя это потребует значительных усилий, результат стоит того. Наградой станет ускорение разработки программ, улучшение структуры кода, расширяемые программы и сокращение усилий по сопровождению кода.
Интерфейсы
Интерфейсы и абстрактные классы улучшают структуру кода и способствуют отделению интерфейса от реализации.
В традиционных языках программирования такие механизмы не получили особого распространения. Например, в С++ существует лишь косвенная поддержка этих концепций. Сам факт их существования в Java показывает, что эти концепции были сочтены достаточно важными для прямой поддержки в языке.
Мы начнем с понятия абстрактного класса, который представляет собой своего рода промежуточную ступень между обычным классом и интерфейсом. Абстрактные классы — важный и необходимый инструмент для создания классов, содержащих нереализованные методы. Применение «чистых» интерфейсов возможно не всегда.
Абстрактные классы и методы
В примере с классами музыкальных инструментов из предыдущей главы методы базового класса Instrument всегда оставались «фиктивными». Попытка вызова такого метода означала, что в программе произошла какая-то ошибка. Это объяснялось тем, что класс Instrument создавался для определения общего интерфейса всех классов, производных от него.
В этих примерах общий интерфейс создавался для единственной цели— его разной реализации в каждом производном типе. Интерфейс определяет базовую форму, общность всех производных классов. Такие классы, как Instrument, также называют абстрактными базовыми классами или просто абстрактными классами
Если в программе определяется абстрактный класс вроде Instrument, создание объектов такого класса практически всегда бессмысленно. Абстрактный класс создается для работы с набором классов через общий интерфейс. А если Instrument только выражает интерфейс, а создание объектов того класса не имеет смысла, вероятно, пользователю лучше запретить создавать такие объекты. Конечно, можно заставить все методы Instrument выдавать ошибки, но в этом случае получение информации откладывается до стадии выполнения. Ошибки такого рода лучше обнаруживать во время компиляции.
В языке Java для решения подобных задач применяются абстрактные методы1. Абстрактный метод незавершен; он состоит только из объявления и не имеет тела. Синтаксис объявления абстрактных методов выглядит так:
abstract void f;
Класс, содержащий абстрактные методы, называется абстрактным классом. Такие классы тоже должны помечаться ключевым словом abstract (в противном случае компилятор выдает сообщение об ошибке).
Если вы объявляете класс, производный от абстрактного класса, но хотите иметь возможность создания объектов нового типа, вам придется предоставить определения для всех абстрактных методов базового класса. Если этого не сделать, производный класс тоже останется абстрактным, и компилятор заставит пометить новый класс ключевым словом abstract.
Можно создавать класс с ключевым словом abstract даже тогда, когда в нем не имеется ни одного абстрактного метода. Это бывает полезно в ситуациях, где в классе абстрактные методы просто не нужны, но необходимо запретить создание экземпляров этого класса.
Класс Instrument очень легко можно сделать абстрактным. Только некоторые из его методов станут абстрактными, поскольку объявление класса как abstract не подразумевает, что все его методы должны быть абстрактными. Вот что получится:
А вот как выглядит реализация примера оркестра с использованием абстрактных классов и методов:
//. interfaces/music4/Musiс4 java // Абстрактные классы и методы package interfaces.music4; import polymorphism.music.Note, import static net mindview util Print *.
abstract class Instrument {
private int i; // Память выделяется для каждого объекта public abstract void play(Note n); public String whatO { return "Instrument"; } public abstract void adjustO,
}
class Wind extends Instrument { public void play(Note n) {
print("Wind playО " + n),
}
public String whatO { return "Wind"; } public void adjustO {}
}
class Percussion extends Instrument { public void play(Note n) {
printC'Percussion playO " + n).
}
public String whatO { return "Percussion", } public void adjustO {}
}
class Stringed extends Instrument { public void play(Note n) {
print ("Stringed playO " + n),