java 简单工厂模式、多态工厂、抽像工厂 讲解, 代码示例

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)两种模式,我们会在后面讲解它们。
*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值