简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。
简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
一、结构
简单工厂模式就是由一个工厂类根据传入的参量决定创建出哪一种产品类的实例。
- 工厂类(Creator)角色:担任这个角色的是工厂方法模式的核心,含有与应用紧密相关的商业逻辑。工厂类在客户端的直接调用下创建产品对象,它往往由一个具体Java类实现。
- 抽象产品(Product)角色:担任这个角色的类是由工厂方法模式所创建的对象的父类,或它们共同拥有的接口。抽象产品角色可以用一个Java接口或者Java抽象类实现。
- 具体产品(Concrete Product)角色:工厂方法模式所创建的任何对象都是这个角色的实例,具体产品角色由一个具体Java类实现。
/* Creator类源码 */
public class Creator {
public static Product factory() {
return new ConcreteProduct();
}
}
/* Product接口源码 */
public interface Product{}
/* ConcreteProduct类源码 */
public class ConcreteProduct implements Product {
public ConcreteProduct() {}
}
二、实现
抽象产品角色的省略
如果系统仅有一个具体产品角色的话,那么就可以省略掉抽象产品角色。
public class Creator {
public static ConcreteProduct factory() {
return new ConcreteProduct();
}
}
public class ConcreteProduct {
public ConcreteProduct() {}
}
三个角色全部合并
如果抽象产品角色已经被省略,而工厂角色就可以与具体产品角色合并。换言之,一个产品类为自身的工厂。
显然,三个原本独立的角色:工厂角色、抽象产品以及具体产品角色都已经合并成为一个类,这个类自行创建自己的实例。
public class ConcreteProduct {
public ConcreteProduct() {}
public static ConcreteProduct factory() {
return new ConcreteProduct();
}
}
三、优缺点
优点:
模式的核心是工厂类,决定创建哪一个产品类的实例。而客户端免除直接创建产品对象的责任而仅仅负责“消费”产品。实现了对责任的分割。
缺点:
当产品类有复杂的多层次等级结构时,工厂类只有它自己,在何时创建哪一种产品的判断逻辑混合在一起,使得系统在将来进行功能扩展时较为困难。这一缺点在工厂方法模式中得到克服。
简单工厂模式的工厂角色无法形成基于继承的等级结构,因为静态方法无法由子类继承,而简单工厂模式是使用静态方法作为工厂方法的。
“开-闭原则”
“开-闭”原则要求一个系统的设计能够允许系统在无需修改的情况下,扩展其功能。
一个系统总是可以划分成为产品的消费者角色(Client)、产品的工厂角色(Factory)以及产品角色(Product)三个子系统。
在这个系统中,功能的扩展体现在引进新的产品上。“开-闭”原则对于产品的消费角色是成立的,而对于工厂角色是不成立的。
对于产品消费角色来说,任何时候需要某种产品,只需向工厂角色请求即可。而工厂角色在接到请求后,会自行判断创建和提供哪一个产品。所以消费角色无需知道它得到的是哪一种产品;换言之,产品消费角色无需修改就可以接纳新的产品。
对于工厂角色来说,增加新的产品需要知道每一种产品,如何创建它们以及何时向客户端提供它们;换言之,接纳新的产品意味着修改这个工厂角色的源码。
四、例题
使用简单工厂模式设计一个创建不同几何形状,如圆形、方形和三角形实例的描图员(Art Tracer)系统。每个几何图形都要有画出draw()和擦去erase()两个方法。当描图员接到指令,要求创建不支持的几何图形时,要提出BadShapeException异常。
步骤1
创建一个接口,规范出所有的产品类必须实现的方法
public interface Shape {
void draw();
void erase();
}
步骤2
创建实现接口的实体类
public class Square implements Shape {
public void draw() {
System.out.println("Square.draw()");
}
public void erase() {
System.out.println("Square.erase()");
}
}
public class Circle implements Shape {
public void draw() {
System.out.println("Circle.draw()");
}
public void erase() {
System.out.println("Circle.erase()");
}
}
public class Triangle implements Shape {
public void draw() {
System.out.println("Triangle.draw()");
}
public void erase() {
System.out.println("Triangle.erase()");
}
}
// 特别提供一个异常类
public class BadShapeException extends Exception {
public BadShapeException(String msg) {
super(msg);
System.out.println("Unknown pattern: " + msg);
}
}
步骤3
创建一个工厂,生成基于给定信息的实体类的对象
public class ArtTracer {
/**
* 静态工厂方法
*/
public static 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);
}
}
}
步骤4
使用该工厂,通过传递类型信息来获取实体类的对象
public class FactoryPatternDemo {
public static void main(String[] args) {
ArtTracer art = new ArtTracer();
try {
//获取 Circle 的对象,并调用它的 draw 方法
Shape shape1 = art.factory("CIRCLE");
//调用 Circle 的 draw 方法
shape1.draw();
} catch (BadShapeException e) {}
try {
//获取 Triangle 的对象,并调用它的 draw 方法
Shape shape2 = art.factory("TRIANGLE");
//调用 Triangle 的 draw 方法
shape2.draw();
} catch (BadShapeException e) {}
try {
//获取 Square 的对象,并调用它的 draw 方法
Shape shape3 = art.factory("SQUARE");
//调用 Square 的 draw 方法
shape3.draw();
} catch (BadShapeException e) {}
try {
//获取 Diamond 的对象,并调用它的 draw 方法
Shape shape4 = art.factory("DIAMOND");
//调用 Square 的 draw 方法
shape4.draw();
} catch (BadShapeException e) {}
}
}
步骤5
执行程序,输出结果
Circle.draw()
Triangle.draw()
Square.draw()
Unknown pattern: DIAMOND