Посмотрите, насколько приятнее выглядит пример interfaces/Factories.java при использовании безымянных внутренних классов:
//: innerclasses/Factories.java
import static net.mindview.util.Print.*;
interface Service {
void method1();
void method2();
}
interface ServiceFactory {
Service getService();
}
class Implementation1 implements Service {
private Implementation1() {}
public void method1() {print("Implementation1 method1");}
public void method2() {print("Implementation1 method2");}
public static ServiceFactory factory =
new ServiceFactory() {
public Service getService() {
return new Implementation1();
}
};
}
class Implementation2 implements Service {
private Implementation2() {}
public void method1() {print("Implementation2 method1");}
public void method2() {print("Implementation2 method2");}
public static ServiceFactory factory =
new ServiceFactory() {
public Service getService() {
return new Implementation2();
}
};
}
public class Factories {
public static void serviceConsumer(ServiceFactory fact) {
Service s = fact.getService();
s.method1();
s.method2();
}
public static void main(String[] args) {
serviceConsumer(Implementation1.factory);
// Реализации полностью взаимозаменяемы;
serviceConsumer(Implementation2.factory);
}
}
<spoiler text="Output:">
Implementation1 method1
Implementation1 method2
Implementation2 method1
Implementation2 method2
</spoiler> Теперь конструкторы Implementation1 и Implementation2 могут быть закрытыми, и фабрику необязательно оформлять в виде именованного класса. Кроме того, часто бывает достаточно одного фабричного объекта, поэтому в данном случае он создается как статическое поле в реализации Service. Наконец, итоговый синтаксис выглядит более осмысленно. Пример interfaces/Games.java тоже можно усовершенствовать с помощью безымянных внутренних классов:
//: innerclasses/Games.java
// Использование анонимных внутренних классов в библиотеке Game
import static net.mindview.util.Print.*;
interface Game { boolean move(); }
interface GameFactory { Game getGame(); }
class Checkers implements Game {
private Checkers() {}
private int moves = 0;
private static final int MOVES = 3;
public boolean move() {
print("Checkers move " + moves);
return ++moves != MOVES;
}
public static GameFactory factory = new GameFactory() {
public Game getGame() { return new Checkers(); }
};
}
class Chess implements Game {
private Chess() {}
private int moves = 0;
private static final int MOVES = 4;
public boolean move() {
print("Chess move " + moves);
return ++moves != MOVES;
}
public static GameFactory factory = new GameFactory() {
public Game getGame() { return new Chess(); }
};
}
public class Games {
public static void playGame(GameFactory factory) {
Game s = factory.getGame();
while(s.move())
;
}
public static void main(String[] args) {
playGame(Checkers.factory);
playGame(Chess.factory);
}
}
<spoiler text="Output:">
Checkers move 0
Checkers move 1
Checkers move 2
Chess move 0
Chess move 1
Chess move 2
</spoiler> Вспомните совет, данный в конце предыдущей главы: отдавать предпочтение классам перед интерфейсами. Если архитектура системы требует применения интерфейса, вы это поймете. В остальных случаях не применяйте интерфейсы без крайней необходимости.