junhong

Design Pattern with java (part two)

Encapsulating creation


Although only the Simple Factory Method is a true singleton, you’ll find that each specify
factory class in the more general types of factories will only have a single instance.
  1. Simple Factory method
    One approach is to make the factory a static method of the base class:
    //: factory:shapefact1:ShapeFactory1.java
    // A simple static factory method.
    package factory.shapefact1;
    import java.util.*;
    import junit.framework.*;
    abstract class Shape {
    public abstract void draw();
    public abstract void erase();
    public static Shape factory(String type) {
    if(type.equals("Circle")) return new Circle();
    if(type.equals("Square")) return new Square();
    throw new RuntimeException(
    "Bad shape creation: " + type);
    }
    }
    class Circle extends Shape {Circle() {} // Package-access constructor
    public void draw() {
    System.out.println("Circle.draw");
    }
    public void erase() {
    System.out.println("Circle.erase");
    }
    }
    class Square extends Shape {
    Square() {} // Package-access constructor
    public void draw() {
    System.out.println("Square.draw");
    }
    public void erase() {
    System.out.println("Square.erase");
    }
    }
    public class ShapeFactory1 extends TestCase {
    String shlist[] = { "Circle", "Square",
    "Square", "Circle", "Circle", "Square" };
    List shapes = new ArrayList();
    public void test() {
    Iterator it = Arrays.asList(shlist).iterator();
    while(it.hasNext())
    shapes.add(Shape.factory((String)it.next()));
    it = shapes.iterator();
    while(it.hasNext()) {
    Shape s = (Shape)it.next();
    s.draw();
    s.erase();
    }
    }
    public static void main(String args[]) {
    junit.textui.TestRunner.run(ShapeFactory1.class);
    }
    } ///:~
    To encourage creation to only happen in the factory( ), the constructors for the specific
    types of Shape are give package access, so factory( ) has access to the constructors but they
    are not available outside the package.
  2. Polymorphic factories
    different types of factories can be subclassed from the basic factory,for example
    interface Shape {
    void draw();
    void erase();
    }
    abstract class ShapeFactory {
    protected abstract Shape create();
    private static Map factories = new HashMap();
    public static void
    addFactory(String id, ShapeFactory f) {
    factories.put(id, f);
    }
    // A Template Method:
    public static final
    Shape createShape(String id) {
    if(!factories.containsKey(id)) {
    try {
    // Load dynamically
    Class.forName("factory.shapefact2." + id);
    } catch(ClassNotFoundException e) {
    throw new RuntimeException(
    "Bad shape creation: " + id);
    }
    // See if it was put in:
    if(!factories.containsKey(id))
    throw new RuntimeException(
    "Bad shape creation: " + id);
    }
    return
    ((ShapeFactory)factories.get(id)).create();
    }
    }
    class Circle implements Shape {
    private Circle() {}
    public void draw() {
    System.out.println("Circle.draw");
    }
    public void erase() {
    System.out.println("Circle.erase");
    }
    private static class Factory
    extends ShapeFactory {
    protected Shape create() {
    return new Circle();
    }
    }
    static {
    ShapeFactory.addFactory(
    "Circle", new Factory());
    }
    }
    .......
  3. Abstract factories
    The Abstract Factory pattern looks like the factory objects we’ve seen previously, with not
    one but several factory methods. Each of the factory methods creates a different kind of
    object. The idea is that at the point of creation of the factory object, you decide how all the
    objects created by that factory will be used.
    As another example suppose you are creating a general-purpose gaming environment and you
    want to be able to support different types of games
    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");
    }
    }
    // The Abstract Factory:
    interface GameElementFactory {Player makePlayer();
    Obstacle makeObstacle();
    }
    // Concrete factories:
    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);
    // These just ensure no exceptions are thrown:
    public void test1() { g1.play(); }
    public void test2() { g2.play(); }
    public static void main(String args[]) {
    junit.textui.TestRunner.run(Games.class);
    }
    } ///:~
    In this environment, Player objects interact with Obstacle objects, but there are different
    types of players and obstacles depending on what kind of game you’re playing. You determine
    the kind of game by choosing a particular GameElementFactory, and then the
    GameEnvironment controls the setup and play of the game. In this example, the setup and
    play is very simple, but those activities (the initial conditions and the state change) can
    determine much of the game’s outcome. Here, GameEnvironment is not designed to be
    inherited, although it could very possibly make sense to do that.

posted on 2006-04-10 23:23 junhong 阅读(502) 评论(0)  编辑  收藏 所属分类: java技术


只有注册用户登录后才能发表评论。


网站导航: