package org.rui.pattern2;
import java.util.*;
import junit.framework.*;
/**
* (实现 factory 模式)常用的方法是把 factory 声明为基类的静态方法(static method)
*
* @author Administrator
*
*/
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);
}
} // /:~
/**
* factory() 方法需要传入一个参数来决定要创建的 Shape 的具体类型; 在上面的
* 例子里(参数)碰巧是一个字符串(String),它也可以是其它任意类型。当加入新 的 Shape
* 类型的时候(我们假定被创建对象的初始化代码是来自系统以外的,而不是 像上面那个例子使用一个硬编码(hard-coded)的数组),系统唯一需要改动的代码
* 就是 factory( )方法。为了促使创建对象的代码只包含在 factory( )方法里,特定类 型的 Shape 类的构造函数都被声明为
* package 权限,这样一来只有 factory( )方法可 以调用这些构造函数,而位于包(package)以外的那部分代码则没有足够的权限(调
* 用这些构造函数)。
*/
package org.rui.pattern2;
import java.util.*;
import junit.framework.*;
/**
* 上例中,静态的 factory( )方法使得所有创建对象的操作都集中在一个地方完
* 成,这也就是唯一需要你修改代码的地方。这当然是一个还算不错的的解决办法,它 封装了创建对象的过程。然而,《设计模式》强调使用 Factory Method
* 是为了使不同 类型的工厂可以由基本类型的工厂派生(subclass)出来(上面例子是一个特例)。
* 但是,那本书没有给出具体例子,只是重复了用于说明抽象工厂(Abstract Factory)的那个例子(你会在本书下一节看到一个 Abstract
* Factory 的例子)。下 面的例子,我们修改了 ShapeFactory1.java 使得工厂方法成为一个单独的类的虚函 数。请注意,特定类型的
* Shape 类是根据需要动态加载的。
*
* @author Administrator
*
*/
interface Shape2
{
void draw();
void erase();
}
abstract class ShapeFactory
{
protected abstract Shape2 create();
private static Map factories = new HashMap();
public static void addFactory(String id, ShapeFactory f)
{
factories.put(id, f);
}
public static final Shape2 createShape(String id)
{
if (!factories.containsKey(id))
{
try
{
// 动态加载
Class.forName("org.rui.pattern2." + id);
} catch (ClassNotFoundException e)
{
e.printStackTrace();
throw new RuntimeException("Bad shape creation: " + id);
}
// 看看这是:
if (!factories.containsKey(id))
throw new RuntimeException("Bad shape creation: " + id);
}
//从加过到集合里获取对象 内部类继承ShapeFactory create返回外部类对象Shape2
return ((ShapeFactory) factories.get(id)).create();
}
}
// -------------------------------------------------------------------
class Circle2 implements Shape2
{
private Circle2()
{
}
public void draw()
{
System.out.println("Circle.draw");
}
public void erase()
{
System.out.println("Circle.erase");
}
//内部类
private static class Factory extends ShapeFactory
{
//返回外部类对象
protected Shape2 create()
{
return new Circle2();
}
}
// 初始化时把对象加入工厂Map集合中
static
{
ShapeFactory.addFactory("Circle", new Factory());
}
}
// ---------------------------------------------------------------------------
class Square2 implements Shape2
{
private Square2()
{
}
public void draw()
{
System.out.println("Square.draw");
}
public void erase()
{
System.out.println("Square.erase");
}
private static class Factory extends ShapeFactory
{
protected Shape2 create()
{
return new Square2();
}
}
static
{
ShapeFactory.addFactory("Square2", new Factory());
}
}
// --------------------------------------------------
public class ShapeFactory2 extends TestCase
{
String shlist[] = { "Circle2", "Square2", "Square2", "Circle2", "Circle2",
"Square2" };
List shapes = new ArrayList();
public void test()
{
// T这只是确保它将完成
// 没有抛出异常
Iterator it = Arrays.asList(shlist).iterator();
while (it.hasNext())
shapes.add(ShapeFactory.createShape((String) it.next()));
it = shapes.iterator();
while (it.hasNext())
{
Shape2 s = (Shape2) it.next();
s.draw();
s.erase();
}
}
public static void main(String args[])
{
junit.textui.TestRunner.run(ShapeFactory2.class);
}
} // /:~
/**
* 现在工厂方法(factory method)出现在它自己的类 ShapeFactory 里,名字改成了 create(
* )方法。它是一个受保护的(protected)方法,也就是说它不能被直接调 用,但可以被重载。Shape 类的子类必须创建与之对应的
* ShapeFactory 的子类,并且 通过重载 create( )函数来创建它自己的实例。实际上一系列 Shape 对象的创建是通过 调用
* ShapeFactory.createShape( ) 来完成的。 CreateShape( )是个静态方法, 它 根据传入的标示,通过查找
* ShapeFactory 的 Map 成员变量找到与之相应的工厂对 象 (factory obejct)。 然后,找到的 factory 对象即被用来创建
* shape 对象,但 你可以想象一下更为棘手的问题:(与某种 Shape 类型相对应的)工厂对象被调用者
* 用来以更为复杂的方式创建对象。但是,大多数情况下你似乎并不需要用到复杂的多 态工厂方法(polymorphic factory
* method),在基类里加一个静态方法(像 ShapeFactory1.java 那样)就足以解决问题了。
*
* 注意到,ShapeFactory 的初始化必须通过加载 Map 数据成员才能完成(Map 的元 素是 factory 对象),而这些初始化代码又位于
* Shape 实现类的静态初始化语句里。 这样一来,每加入一个新的类型你就必须得继承原来的类型(指 Shape?),创建一个
* factory,然后添加静态初始化语句用以加载 Map 对象。这些额外的复杂性又一次暗示 我们:如果不需要创建单独的 factory
* 对象,那最好还是使用静态工厂方法。
*/
---------------------------------------------------------------
package org.rui.pattern2;
/**
* 抽象工厂(Abstract factories)
*/
interface Obstacle
{
void action();
}
interface Player
{
void interactWith(Obstacle o);
}
class Kitty implements Player
{
public void interactWith(Obstacle ob)
{
System.out.println("Kitty has encountered a ");
ob.action();
}
}
class KungFuGuy implements Player
{
public void interactWith(Obstacle ob)
{
System.out.println("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;
/**
* 通过工厂获得需要的对象实例
* @param factory
*/
public GameEnvironment(GameElementFactory factory)
{
gef = factory;
p = factory.makePlayer();
ob = factory.makeObstacle();
//System.out.println("ob:"+ob);
}
public void play()
{
p.interactWith(ob);
}
}
package org.rui.pattern2;
import junit.framework.TestCase;
/**
抽象工厂(abstract factory)模式看起来很像前面我们看到的那些 factory 对
象,只不过它有多个而不是一个 factory 方法。每一个 factory 方法创建一个不同类
型的对象。基本思想是:在创建工厂对象的地方,由你来决定如何使用该工厂对象创
建的那些对象。《设计模式》里给出的例子实现了在不同用户图形界面(GUIs)之间
的可移植性:你根据自己使用的 GUI 来创建一个与之对应的 factory 对象,在这以
后,当你需要用到菜单,按钮,滚动条这些东西的时候,它会根据你使用的 GUI 自动
创建合适的对象。这样,你就可以把实现不同 GUI 之间切换的代码分离出来,使它集
中在一个地方。
作为另外一个例子,假设你要创建一个通用的游戏环境,而且你还想要支持不同
类型的游戏。下面的例子用抽象工厂给出了它的一种可能的实现。
* @author Administrator
*
*/
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);
}
} // /:~
/**
在上面的游戏环境里,Player 对象与 Obstale 对象交互,根据你所选择的游戏类
型,player 和 obstacle 的各自类型也会不同。你通过选择某个特定的
GameElementFactory 来决定游戏的类型,然后 GameElementFactory 会控制初始化和游
戏的进行。在上面的例子里,初始化和游戏的进行都非常简单,但那些活动(初始条
件和状态变化)可以在很大程度上决定游戏的结局。这里,GameEnvironment 不是用来
给其它类继承的 ,尽管那么做很可能也说的通。
上面的代码也包含了双重分派(Double Dispatching)和工厂方法(Factory
Method)两种模式,我们会在后面讲解它们。
*/