在平时的应用开发中,工厂模式是比较常用的一个设计模式,基本上在很多的开源jar中可以看到工厂设计模式的影子。
工厂模式专门负责将大量有共同接口的类实例化。工厂模式可以动态决定哪一个类实例化,不必事先知道每次要实例化哪一个类。工厂模式有以下几种形态:
本文介绍简单工厂模式和工厂方法模式。
简单工厂模式就是由一个工厂类根据传入的参数决定创建出哪一个产品类的实例。
package com.wangmengjun.tutorial.designpattern.factory;
public abstract class AbstractFileHandler {
//public abstract void handle(InputStream is);
public abstract void handle();
}
package com.wangmengjun.tutorial.designpattern.factory;
public class ExcelHandler extends AbstractFileHandler {
@Override
public void handle() {
System.out.println("处理Excel文件");
}
}
CsvHandler.java
package com.wangmengjun.tutorial.designpattern.factory;
public class CsvHandler extends AbstractFileHandler {
@Override
public void handle() {
System.out.println("处理CSV文件");
}
}
包含一个静态方法,用于根据文件后缀获取不同的Handler
package com.wangmengjun.tutorial.designpattern.factory;
public class FileHandlerFactory {
public static AbstractFileHandler getFileHandler(FileType type) {
if (FileType.EXCEL == type) {
return new ExcelHandler();
} else if (FileType.CSV == type) {
return new CsvHandler();
}
throw new IllegalArgumentException("file type is illeegal");
}
}
package com.wangmengjun.tutorial.designpattern.factory;
public enum FileType {
EXCEL, CSV, PDF;
}
测试一下
package com.wangmengjun.tutorial.designpattern.factory;
public class Client {
public static void main(String[] args) {
String suffix = "xls";
AbstractFileHandler handler = FileHandlerFactory.getFileHandler(suffix);
//处理2003版本的Excel文件
handler.handle();
suffix = "xlsx";
handler = FileHandlerFactory.getFileHandler(suffix);
//处理2007版本以上的Excel文件
handler.handle();
suffix = "csv";
handler = FileHandlerFactory.getFileHandler(suffix);
//处理CSV文件
handler.handle();
}
}
简单工厂模式特点
优点:
将创建实例的工作与使用实例的工作分开,使用者不必关心类对象如何创建,实现了解耦。把初始化实例时的工作放到工厂里进行,使代码更容易维护。更符合面向对象的原则 & 面向接口编程,而不是面向实现编程。
缺点:
简单工厂模式的核心工厂类,这个类集中了所有的产品创建逻辑,需要判断在什么时候创建某种产品,当有新的产品需要增加的时候,不得不修改这个核心工厂类的代码。如上述示例中,再增加一个Pdf的文件处理器类PdfHandler,就需要在工厂类中增加判断逻辑。
另外,简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。
上述提到问题,将在工厂方法模式(Factory Method)中得到解决,接下来,一起来看下工厂方法模式。
意图
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
结构
工厂方法模式的基本结构如下:
这里涉及到的参与者有如下几种:
接下来我们来简单调整一下上述代码,采用工厂方法的模式进行展开。
package com.wangmengjun.tutorial.designpattern.factory;
public abstract class AbstractFileHandler {
//public abstract void handle(InputStream is);
public abstract void handle();
}
package com.wangmengjun.tutorial.designpattern.factory;
public class ExcelHandler extends AbstractFileHandler {
@Override
public void handle() {
System.out.println("处理Excel文件");
}
}
package com.wangmengjun.tutorial.designpattern.factory;
public class CsvHandler extends AbstractFileHandler {
@Override
public void handle() {
System.out.println("处理CSV文件");
}
}
package com.wangmengjun.tutorial.designpattern.factory;
public abstract class AbstractFileHandlerFactory {
protected abstract AbstractFileHandler createFileHandler();
}
package com.wangmengjun.tutorial.designpattern.factory;
public class CsvHandlerFactory extends AbstractFileHandlerFactory {
@Override
protected AbstractFileHandler createFileHandler() {
System.out.println("创建CsvHandler对象");
return new CsvHandler();
}
}
package com.wangmengjun.tutorial.designpattern.factory;
public class ExcelHandlerFactory extends AbstractFileHandlerFactory {
@Override
protected AbstractFileHandler createFileHandler() {
System.out.println("创建ExcelHandler对象");
return new ExcelHandler();
}
}
package com.wangmengjun.tutorial.designpattern.factory;
public class Client2 {
public static void main(String[] args) {
//Excel处理器
AbstractFileHandlerFactory handler = new ExcelHandlerFactory();
handler.createFileHandler().handle();
//csv处理器
handler = new CsvHandlerFactory();
handler.createFileHandler().handle();
}
}
运行一下:
创建ExcelHandler对象 处理Excel文件 创建CsvHandler对象 处理CSV文件
至此,一个简单的工厂方法模式示例就完成了。再来看下,对新增加产品如PdfHandler,我们需要做什么呢?
1、新建文件处理器PdfHandler
package com.wangmengjun.tutorial.designpattern.factory;
public class PdfHandler extends AbstractFileHandler {
@Override
public void handle() {
System.out.println("处理PDF文件");
}
}
2、新建一个Pdf创建工厂,用于创建PdfHandler
package com.wangmengjun.tutorial.designpattern.factory;
public class PdfHandlerFactory extends AbstractFileHandlerFactory {
@Override
protected AbstractFileHandler createFileHandler() {
System.out.println("创建PdfHandler对象");
return new PdfHandler();
}
}
然后,客户端调用只要:
AbstractFileHandlerFactory pdfHandler = new ExcelHandlerFactory();
pdfHandler.createFileHandler().handle();
可见:加入一个新的产品,那么就是向系统中加入这个产品类以及它对应的工厂类。没有必要修改客户端,也没有必要修改抽象工厂角色或者其他已有的具体工厂角色。对于增加新的产品类而言,这个系统完全支持开闭原则。
简单工厂模式 vs 工厂方法模式
1、工厂模式和简单工厂模式在结构上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。工厂方法模式可以允许很多具体工厂类从抽象工厂类中将创建行为继承下来,从而可以成为多个简单工厂模式的综合,进而推广了简单工厂模式。
2、加入一个新的产品,在工厂方法模式中没有必要修改客户端,也没有必要修改抽象工厂角色或者其他已有的具体工厂角色。对于增加新的产品类而言,这个系统完全支持开闭原则。而简单工厂模式则需要对核心的工厂类增加判断语句以支持新加入的产品。
工厂方法模式针对的是一个产品等级结构,如果需要面对多个产品等级结构,怎么办呢?我们将在下一篇《抽象工厂模式浅析》文章中讲述。
参考
[1]. 阎宏. Java与模式.电子工业出版社
[2]. Erich Gamma. 设计模式-可复用面向对象软件的基础. 机械工业出版社.