Шаблон Абстрактной Фабрики выглядит так же, как фабрика объектов, рассмотренная в предыдущем разделе, но не с одним, а с несколькими методами фабрики. Каждый из методов фабрики создает объект различного рода. Эта идея состоит в том, что в момент создания объекта фабрики вы решаете как все объекты, созданные фабрикой, будут использованы. Пример, данный в книге Design Patterns реализует вероятность использования различных графических интерфейсов пользователя (GUI). Вы создаете объект фабрики для того GUI, с которым вы работаете, а из него по запросу автоматически создаете меню, кнопку, слайдер и т. п. в соответствии с версией GUI. Таким образом вы способны изолировать в одном месте эффект изменения GUI.
Другой, предлагаемый вам пример, состоит в создании игровой среды общего назначения, в которой вы хотите иметь возможность поддерживать различные типы игр. Здесь описано, как это может выглядеть с использованием абстрактной фабрики:
//: factory:Games.java
// Пример шаблона Абстрактной фабрики.
package factory;
import junit.framework.*;
interface Obstacle {
void action();
}
interface Player {
void interactWith(Obstacle o);
}
class Kitty implements Player {
public void interactWith(Obstacle ob) {
System.out.print("Kitty has encountered a ");
ob.action();
}
}
class KungFuGuy implements Player {
public void interactWith(Obstacle ob) {
System.out.print("KungFuGuy now battles a ");
ob.action();
}
}
class Puzzle implements Obstacle {
public void action() {
System.out.println("Puzzle");
}
}
class NastyWeapon implements Obstacle {
public void action() {
System.out.println("NastyWeapon");
}
}
// Абстрактная фабрика:
interface GameElementFactory {
Player makePlayer();
Obstacle makeObstacle();
}
// Конкретный фабрики:
class KittiesAndPuzzles implements GameElementFactory {
public Player makePlayer() {
return new Kitty();
}
public Obstacle makeObstacle() {
return new Puzzle();
}
}
class KillAndDismember implements GameElementFactory {
public Player makePlayer() {
return new KungFuGuy();
}
public Obstacle makeObstacle() {
return new NastyWeapon();
}
}
class GameEnvironment {
private GameElementFactory gef;
private Player p;
private Obstacle ob;
public GameEnvironment(GameElementFactory factory) {
gef = factory;
p = factory.makePlayer();
ob = factory.makeObstacle();
}
public void play() {
p.interactWith(ob);
}
}
public class Games extends TestCase {
GameElementFactory kp = new KittiesAndPuzzles(),
kd = new KillAndDismember();
GameEnvironment g1 = new GameEnvironment(kp), g2 = new GameEnvironment(kd);
// Здесь просто убеждаемся что не было выброшено исключений:
public void test1() {
g1.play();
}
public void test2() {
g2.play();
}
public static void main(String args[]) {
junit.textui.TestRunner.run(Games.class);
}
} // /:~
В этой среде объект Player взаимодействует с объектом Obstacle, но есть разные типы игроков и препятствий в зависимости от рода игры, в которую вы играете. Вы определяете род игры путем создания определенного класса GameElementFactory, а затем GameEnvironment управляет установками и ходом игры. В этом примере установка и ход игры очень просты, но активность (начальные состояния и изменение состояния) может определять многое в ходе игры. Здесь класс GameEnvironment не предназначен для наследования, хотя нельзя исключить возможность сделать так.
Здесь также содержится примеры Двойной Диспетчеризации и Метода Фабрики (Factory method), которые будут объяснены позже.
← | Полиморфные фабрики (Polymorphic factories) | Упражнения | → |