Абстрактная фабрика (Abstract factories)


Шаблон Абстрактной Фабрики выглядит так же, как фабрика объектов, рассмотренная в предыдущем разделе, но не с одним, а с несколькими методами фабрики. Каждый из методов фабрики создает объект различного рода. Эта идея состоит в том, что в момент создания объекта фабрики вы решаете как все объекты, созданные фабрикой, будут использованы. Пример, данный в книге 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), которые будут объяснены позже.