StringBuffer s = new StringBuffer(1000); |
就创立了一个对象s,其类型是StringBuffer。使用new操作符的短处是事先必须明确知道要实例化的类是什么, 而且实例化的责任往往与使用实例的责任不加区分。使用创立性模式将类实例化,首先不必事先知道每次是要实例化哪一个类, 其次把实例化的责任与使用实例的责任分割开来,可以弥补直接使用new操作符的短处。
而工厂模式就是专门负责将大量有共同接口的类实例化,而且不必事先知道每次是要实例化哪一个类的模式。
工厂模式有几种形态
工厂模式有以下几种形态:
简单工厂(Simple Factory)模式
工厂方法(Factory Method)模式,又称多形性工厂(Polymorphic Factory)模式
抽象工厂(Abstract Factory)模式,又称工具箱(Kit或Toolkit)模式.
介绍简单工厂模式
比如说,你有一个描述你的后花园的系统,在你的后花园里有各种的花,但还没有水果。你现在要往你的系统里引进一些新的类,用来描述下列的水果:
葡萄 Grapes
草莓 Strawberry
萍果 Apple
花和水果最大的不同,就是水果最终是可以采摘食用的。那么,很自然的作法就是建立一个各种水果都适用的接口,这样一来这些水果类作为相似的数据类型就可以和你的系统的其余部分,如各种的花有所不同,易于区分。
![]() 图1. Grape, Strawberry和Apple是拥有共同接口FruitIF的类 |
package com.javapatterns.simplefactory; public interface FruitIF { void grow(); void harvest(); void plant(); String color = null; String name = null; } |
package com.javapatterns.simplefactory; public class Apple implements FruitIF { public void grow() { log("Apple is growing..."); } public void harvest() { log("Apple has been harvested."); } public void plant() { log("Apple has been planted."); } public static void log(String msg) { System.out.println(msg); } public int getTreeAge(){ return treeAge; } public void setTreeAge(int treeAge){ this.treeAge = treeAge; } private int treeAge; } |
package com.javapatterns.simplefactory; public class Grape implements FruitIF { public void grow() { log("Grape is growing..."); } public void harvest() { log("Grape has been harvested."); } public void plant() { log("Grape has been planted."); } public static void log(String msg) { System.out.println(msg); } public boolean getSeedful() { return seedful; } public void setSeedful(boolean seedful) { this.seedful = seedful; } private boolean seedful; } |
package com.javapatterns.simplefactory; public class Strawberry implements FruitIF { public void grow() { log("Strawberry is growing..."); } public void harvest() { log("Strawberry has been harvested."); } public void plant() { log("Strawberry has been planted."); } public static void log(String msg) { System.out.println(msg); } } |
你作为小花果园的主人兼园丁,也是系统的一部分,自然要由一个合适的类来代表,这个类就是 FruitGardener类。这个类的结构请见下面的UML类图。
图2. FruitGardener类图。 |
代码清单5. FruitGardener类的源代码。
代码清单6. BadFruitException类的源代码。 在使用时,只须呼叫FruitGardener的factory()方法即可
就这样你的小果园一定会有百果丰收啦! |
简单工厂模式的定义
总而言之,简单工厂模式就是由一个工厂类根据参数来决定创立出那一种产品类的实例。下面的UML类图就精确定义了简单工厂模式的结构。
![]() 图4. 简单工厂模式定义的类图。 |
public class Creator { public Product factory() { return new ConcreteProduct(); } } public interface Product { } public class ConcreteProduct implements Product { public ConcreteProduct(){} } |
问答题
在本节开始时不是说,工厂模式就是在不使用new操作符的情况下,将......类实例化的吗, 可为什么在具体实现时,仍然使用了new操作符呢?
在本节的小果园系统里有三种水果类,可为什么在图3.(简单工厂模式定义的类图) 中产品(Product)类只有一种呢?
请使用简单工厂模式设计一个创立不同几何形状,如圆形,方形和三角形实例的描图员(Art Tracer)系统。每个几何图形都要有画出draw()和擦去erase()两个方法。当描图员接到指令,要求创立不支持的几何图形时,要提出BadShapeException例外。
请简单举例说明描图员系统怎样使用。
在简单工厂模式的定义(见图4)中和花果园例子中,factory()方法都是属于实例的, 而非静态的或是类的方法。factory()方法可不可以是静态的方法呢?
问答题答案
对整个系统而言,工厂模式把具体使用new操作符的细节包装和隐藏起来。当然只要程序是用爪哇语言写的, 爪哇语言的特征在细节里一定会出现的。
图3.(简单工厂模式定义的类图),是精减后的框架性类图,用于给出这一模式的准确而精练的定义。产品(Product)类到底会有几种,则要对每个系统作具体分析。
这里给出问题的完整答案。描图员(Art Tracer)系统的UML如下
系统的源代码如下 |
package com.javapatterns.simplefactory.exercise; public class ArtTracer { public Shape factory(String which) throws BadShapeException { if (which.equalsIgnoreCase("circle")) { return new Circle(); } else if (which.equalsIgnoreCase("square")) { return new Square(); } else if (which.equalsIgnoreCase("triangle")) { return new Triangle(); } else { throw new BadShapeException(which); } } } |
package com.javapatterns.simplefactory.exercise; public interface Shape { void draw(); void erase(); } |
package com.javapatterns.simplefactory.exercise; public class Square implements Shape { public void draw() { System.out.println("Square.draw()"); } public void erase() { System.out.println("Square.erase()"); } } |
package com.javapatterns.simplefactory.exercise; public class Circle implements Shape { public void draw() { System.out.println("Circle.draw()"); } public void erase() { System.out.println("Circle.erase()"); } } |
package com.javapatterns.simplefactory.exercise; public class Triangle implements Shape { public void draw() { System.out.println("Triangle.draw()"); } public void erase() { System.out.println("Triangle.erase()"); } } |
package com.javapatterns.simplefactory.exercise; public class BadShapeException extends Exception { public BadShapeException(String msg) { super(msg); } } |
try { ArtTracer art = new ArtTracer(); art.factory("circle"); art.factory("square"); art.factory("triangle"); art.factory("diamond"); } catch(BadShapeException e) { ... } |