介绍
简单工厂模式是类的创建模式,又叫静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品的实例。
模式角色
简单工厂模式有以下角色:
- Creator(工厂类),核心部分,负责实现创建所有产品的内部逻辑,工厂类可以被外界直接调用,创建所需对象。
- Product(抽象产品),担任这个角色的类是由工厂方法模式所创建的对象的父类,或它们共同拥有的接口。抽象产品角色可以用一个Java接口(标记接口(如Cloneable、Serializable等是标记接口))或者Java抽象类实现。
- ConcreteProduct(具体产品),工厂方法模式所创建的任何对象都是这个角色的实例。
模式结构图
模式实现
模式实现,下面通过伪代码去实现该模式:
模拟移动端的View框架或者说需要写一个有多端风格的GUI框架(Android风格、iOS风格),这个系统有显示文本的TextView控件,显示一个按钮的Button控件,显示一个列表、一个圆…
/**
* 简单工厂模式
*/
public class SimpleFactory {
// 静态的工厂方法
public static SimpleFactoryView factory(String witch) throws BadSimpleFactoryViewException {
if ("AndroidTextView".equalsIgnoreCase(witch)) {
return new SimpleFactoryAndroidTextView();
} else if ("AndroidButton".equalsIgnoreCase(witch)) {
return new SimpleFactoryAndroidButton();
} else if ("IOSTextView".equalsIgnoreCase(witch)) {
return new SimpleFactoryIOSTextView();
} else if ("IOSButton".equalsIgnoreCase(witch)) {
return new SimpleFactoryIOSButton();
} else {
throw new BadSimpleFactoryViewException("Bad View request");
}
}
}
class BadSimpleFactoryViewException extends Exception {
public BadSimpleFactoryViewException(String message) {
super(message);
}
}
/**
* 抽象产品
* 控件基类-View
*/
abstract class SimpleFactoryView {
private int width;
private int height;
public SimpleFactoryView() {
}
public SimpleFactoryView(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public abstract void onDraw();
}
/**
* 具体产品
* Android风格-TextView
*/
class SimpleFactoryAndroidTextView extends SimpleFactoryView {
// 显示的文本
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
@Override
public void onDraw() {
System.out.println("绘制文本");
}
}
/**
* 具体产品
* iOS风格-TextView
*/
class SimpleFactoryIOSTextView extends SimpleFactoryView {
// 可用和禁用两种状态
private boolean enable;
@Override
public void onDraw() {
System.out.println("绘制按钮");
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
}
/**
* 具体产品
* Android风格-Button
*/
class SimpleFactoryAndroidButton extends SimpleFactoryView {
// 显示的文本
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
@Override
public void onDraw() {
System.out.println("绘制文本");
}
}
/**
* 具体产品
* iOS风格-Button
*/
class SimpleFactoryIOSButton extends SimpleFactoryView {
// 可用和禁用两种状态
private boolean enable;
@Override
public void onDraw() {
System.out.println("绘制按钮");
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
}
/**
* Client
*/
class SimpleFactoryClient {
public static void main(String[] args) throws BadSimpleFactoryViewException {
SimpleFactoryView view = SimpleFactory.factory("TextView");
view.onDraw();
view = SimpleFactory.factory("Button");
view.onDraw();
}
}
多层次的产品结构
抽象产品使用Java接口或者Java抽象类
模式多个工厂方法
每个工厂类可以有多于一个的工厂方法,分别负责创建不同的产品对象。比如java.text.DateFormat类是其子类的工厂类,而DateFormat类就提供了多个静态工厂方法(DateFormat.getInstance()、DateFormat.getDateInstance()、DateFormat.getTimeInstance()…)。
模式退化
省略抽象产品角色,如果系统仅有一个具体产品角色的话,那么就可以省略掉抽象产品角色。
抽象产品角色与工厂角色合并。比如java.text.DateFormat类,一个抽象产品类同时是子类(SimpleDateFormat)的工厂。博文后面有关于DateFormat的源码介绍。
三个角色合并,如果抽象产品角色已经被省略,而工厂角色就可以与具体产品角色合并。换言之,一个产品类为自身的工厂。显然,三个原本独立的角色:工厂角色、抽象产品角色以及具体产品角色都已经合并成为一个类,这个类自行创建自己的实例。
/**
* 简单抽象工厂模式,三个角色合并
*/
class SimpleFactoryConcreteProduct {
public SimpleFactoryConcreteProduct() {
}
public static SimpleFactoryConcreteProduct factory() {
return new SimpleFactoryConcreteProduct();
}
}
产品对象的循环使用和登记式的工厂方法
在很多情况下,产品对象可以循环使用。换言之工厂方法可以循环使用已经创建出来的对象,而不是每一次都创建新的对象。工厂方法可以通过登记它所创建的产品对象来达到循环使用产品对象的目的。
模式的优点和缺点
优点:
- 模式的核心是工厂类。这个类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例。而客户端可以免除直接创建产品对象的责任,而仅仅负责“消费”产品。简单工厂模式通过这种做法实现了对责任的分割。
- 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
- 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性(不符合开闭原则)。
缺点:
- 当产品类有复杂的多层次结构时,工厂类只有它自己。以不变应万变就是模式的缺点。
- 这个工厂类集中了所有的产品创建逻辑,形成了一个无所不知的全能类。违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。
- 当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;
- 由于简单工厂模式中使用静态方法作为工厂方法,而静态方法无法由子类继承,因此工厂角色无法形成基于继承的等级结构。
- 当新增产品时,无需修改抽象产品源码就能新增产品,但是需要修改工厂源代码,所以简单工厂只在有限的程度上支持“开-闭”原则。
DateFormat部分源码如下:
public abstract class DateFormat extends Format {
---省略源码---
DateFormat.getInstance(){
// 省略源码
}
DateFormat.getDateInstance(){
// 省略源码
}
DateFormat.getDateInstance(int style){
// 省略源码
}
DateFormat.getDateInstance(int style, Locale aLocale){
// 省略源码
}
DateFormat.getTimeInstance(){
// 省略源码
}
DateFormat.getTimeInstance(int style){
// 省略源码
}
DateFormat.getTimeInstance(int style, Locale aLocale){
// 省略源码
}
DateFormat.getDateTimeInstance(){
// 省略源码
}
DateFormat.getDateTimeInstance(int style){
// 省略源码
}
DateFormat.getDateTimeInstance(int style, Locale aLocale){
// 省略源码
}
---省略源码---
}