Эккель Брюс
Шрифт:
interface Service { void methodic), void method2,
}
interface SemceFactory { Service getServiceO;
}
class Implementationl implements Service { private ImplementationlO {}
public void methodic) {printC"Implementationl methodl");} public void method2 {print("Implementationl method2");}
public static ServiceFactory factory = new ServiceFactoryO {
public Service getServiceO {
return new ImplementationlO;
class Implementation2 implements Service { private Implementation20 {}
public void methodlO {print("Implementation2 methodl"),) public void method2 {print("Implementation2 method2"),j public static ServiceFactory factory = new ServiceFactoryO {
public Service getServiceO {
return new Implementation2;
public class Factories {
public static void serviceConsumer(ServiceFactory fact) { Service s = fact.getServiceO; s methodlO; s method2;
}
public static void main(String[] args) {
serviceConsumer(Implementationl.factory); // Реализации полностью взаимозаменяемы: servi ceConsumer(Implementati on2.factory);
}
} /* Output-Implementationl methodl Implementationl method2 Implementation2 methodl Implementation2 method2 */// ~
Теперь конструкторы Implementationl и Implementation2 могут быть закрытыми, и фабрику необязательно оформлять в виде именованного класса. Кроме того, часто бывает достаточно одного фабричного объекта, поэтому в данном случае он создается как статическое поле в реализации Service. Наконец, итоговый синтаксис выглядит более осмысленно.
Пример interfaces/Games.java тоже можно усовершенствовать с помощью безымянных внутренних классов:
//. innerclasses/Games.java
// Использование анонимных внутренних классов в библиотеке Game import static net.mindview.util.Print.*;
interface Game { boolean moveO; } interface GameFactory { Game getGameO; }
class Checkers implements Game { private Checkers О {} private int moves = 0;
private static final int MOVES = 3; продолжение &
class Chess implements Game { private ChessO {} private int moves = 0; private static final int MOVES = 4; public boolean moveO {
print("Chess move " + moves); return ++moves != MOVES;
}
public static GameFactory factory = new GameFactoryO { public Game getGameO { return new ChessO; }
}:
}
public class Games {
public static void piayGame(GameFactory factory) { Game s = factory.getGameO; while(s. moveO)
}
public static void main(String[] args) { pi ayGame(Checkers.factory); piayGame(Chess.factory);
}
} /* Output: Checkers move 0 Checkers move 1 Checkers move 2 Chess move 0 Chess move 1 Chess move 2 Chess move 3 *///•-
Вспомните совет, данный в конце предыдущей главы: отдавать предпочтение классам перед интерфейсами. Если архитектура системы требует применения интерфейса, вы это поймете. В остальных случаях не применяйте интерфейсы без крайней необходимости.
Вложенные классы
public boolean moveО {
print("Checkers move " + moves); return ++moves != MOVES;
}
public static GameFactory factory = new GameFactoryO { public Game getGameO { return new Checkers О; }
Если связь между объектом внутреннего класса и объектом внешнего класса не нужна, можно сделать внутренний класс статическим (объявить его как static). Часто такой класс называют вложенным15 (nested). Чтобы понять смысл ключевого слова static в отношении внутренних классов, следует вспомнить, что в объекте обычного внутреннего класса тайно хранится ссылка на объект создавшего его объемлющего внешнего класса. При использовании статического внутреннего класса такой ссылки не существует. Применение статического внутреннего класса означает следующее:
• для создания объекта статического внутреннего класса не нужен объект внешнего класса;
• из объекта вложенного класса нельзя обращаться к не-статическим членам внешнего класса.
Есть и еще одно различие между вложенными и обычными внутренними классами. Поля и методы обычного внутреннего класса определяются только на уровне внешнего класса, поэтому обычные внутренние классы не могут содержать статические данные, поля и классы. Но вложенные классы не имеют таких ограничений:
//• i nnerclasses/Parcel 11.java