Эккель Брюс
Шрифт:
}
public class Games {
public static void playGame(GameFactory factory) {
Game s = factory.getGameO; продолжение & while(s.moveO)
}
public static void main(String[] args). { playGame(new CheckersFactoryO); playGame(new ChessFactoryO);
}
} /* Output: Checkers move 0 Checkers move 1 Checkers move 2 Chess move 0 Chess move 1 Chess move 2 Chess move 3 *///:-
Если класс Games представляет сложный блок кода, такое решение позволит повторно использовать его для разных типов игр.
В следующей главе будет представлен более элегантный способ реализации фабрик на базе анонимных внутренних классов.
Резюме
После первого знакомства интерфейсы выглядят так хорошо, что может показаться, будто им всегда следует отдавать предпочтение перед реальными классами. Конечно, в любой ситуации, когда вы создаете класс, вместо него можно создать интерфейс и фабрику.
Многие программисты поддались этому искушению. Тем не менее любая абстракция должна быть мотивирована реальной потребностью. Основное назначение интерфейсов — возможность переработки реализации в случае необходимости, а не введение лишнего уровня абстракции вместе с дополнительными сложностями. Дополнительные сложности могут оказаться довольно существенными. А представьте, что кто-то будет вынужден разбираться в вашем коде и в конечном итоге поймет, что интерфейсы были добавлены «на всякий случай», без веских причин — в таких ситуациях все проектирование, которое выполнялось данным разработчиком, начинает выглядеть довольно сомнительно.
В общем случае рекомендуется отдавать предпочтение классам перед интерфейсами. Начните с классов, а если необходимость интерфейсов станет очевидной — переработайте архитектуру своего проекта. Интерфейсы — замечательный инструмент, но ими нередко злоупотребляют.
Внутренние (j
классы кМэ vv
Определение класса может размещаться внутри определения другого класса. Такие классы называются внутренними (inner class).
Внутренние классы весьма полезны, так как они позволяют группировать классы, логически принадлежащие друг другу, и управлять доступом к ним. Однако следует понимать, что внутренние классы заметно отличаются от композиции.
На первый взгляд создается впечатление, что внутренние классы представляют собой простой механизм сокрытия кода. Однако вскоре вы узнаете, что возможности внутренних классов гораздо шире (они знают о существовании внешних классов и могут работать с ними), а программный код с внутренними классами часто бывает более элегантным и понятным (хотя конечно, этого никто не гарантирует).
В этой главе подробно исследуется синтаксис внутренних классов. Эти возможности представлены для полноты материала, хотя, скорее всего, на первых порах они вам не понадобятся. Возможно, начальные разделы этой главы содержат все, что вам действительно необходимо знать на этой стадии, а к более подробным объяснениям можно относиться как к справочному, дополнительному материалу.
Создание внутренних классов
Внутренние классы создаются в точности так, как и следовало ожидать, — определение класса размещается внутри окружающего класса:
//: innerclasses/Parcel 1.java // Создание внутренних классов.
public class Parcel 1 {
class Contents {
private int i = 11,
public int valueO { return i; }
}
class Destination {
private String label, DestinationCString whereTo) { label = whereTo;
}
String readLabeK) { return label; }
}
// Использование внутренних классов имеет много общего // с использованием любых других классов в пределах Parcel 1: public void shipCString dest) {
Contents с = new ContentsO; Destination d = new Destination(dest); System.out.pri ntln(d readLabel),
}
public static void main(String[] args) { Parcel 1 p = new Parcel 10. p.ship("Тасмания").
}
} /* Output: Тасмания *///:-
Если вам понадобится создать объект внутреннего класса где-либо, кроме как в не-статическом методе внешнего класса, тип этого объекта должен задаваться в формате ИмяВнешнегоКласса.ИмяВнутреннегоКласса, что и делается в методе main.
Связь с внешним классом
Пока что внутренние классы выглядят как некоторая схема для сокрытия имен и организации кода — полезная, но не особенно впечатляющая. Однако есть еще один нюанс. Объект внутреннего класса связан с внешним объектом-создателем и может обращаться к его членам без каких-либо дополнительных описаний. Вдобавок для внутренних классов доступны все без исключения элементы внешнего класса14. Следующий пример иллюстрирует сказанное:
//: innerclasses/Sequence,java // Хранение последовательности объектов
interface Selector { boolean endO, Object currentO; void nextO;
}
public class Sequence {
private Object[] objects;
private int next = 0,
public Sequence(int size) { items = new Object[size], }
public void add(Object x) {
if(next < items length)
iterns[next++] = x,
}
private class SequenceSelector implements Selector { private int i = 0.
public boolean endО { return i == items.length; } public Object current О { return i terns [ i D: } public void nextО { if(i < items.length) i++; }