工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一,今天我们一起来彻底解析一下它。
一、介绍
从名称上,顾名思义就是创建产品,按类别分为简单工厂模式、工厂方法模式、抽象工厂模式,主要功能都是帮助我们把对象的实例化操作单独抽取出来,优化系统架构,增强系统的扩展性。
下面,我们一起来看看各个模式的使用方式。
二、简单工厂模式
简单工厂模式,对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过向工厂传递类型来指定要创建的对象。
- 创建一个接口
public interface Product {
void operation1();
void operation2();
}
- 创建实现接口的实体类
public class ConcreateProductA implements Product{
@Override
public void operation1() {
System.out.println("产品A,执行任务1");
}
@Override
public void operation2() {
System.out.println("产品A,执行任务2");
}
}
代码语言:javascript复制public class ConcreateProductB implements Product{
@Override
public void operation1() {
System.out.println("产品B,执行任务1");
}
@Override
public void operation2() {
System.out.println("产品B,执行任务2");
}
}
- 创建一个工厂,生成基于给定信息的实体类的对象
public class SimpleFactory {
//使用 create 方法获取形状类型的对象
public Product create(String productType){
if(productType == null){
return null;
}
if(productType.equalsIgnoreCase("productA")){
return new ConcreateProductA();
}
if(productType.equalsIgnoreCase("productB")){
return new ConcreateProductB();
}
return null;
}
}
- 编写客户端测试类,使用该工厂,通过传递类型信息来获取实体类的对象
public class FactoryPatternDemo {
public static void main(String[] args) {
SimpleFactory simpleFactory = new SimpleFactory();
//获取 productA 的对象
Product productA = simpleFactory.create("productA");
//调用 productA 的 operation1、operation2 方法
productA.operation1();
productA.operation2();
//获取 productB 的对象
Product productB = simpleFactory.create("productB");
//调用 productB 的 operation1、operation2 方法
productB.operation1();
productB.operation2();
}
}
- 执行程序,输出结果:
产品A,执行任务1
产品A,执行任务2
产品B,执行任务1
产品B,执行任务2
当然,还可以将创建对象方式进行改进,将SimpleFactory
类创建对象的方式改成如下方式:
public class SimpleFactory {
//反射机制获取实体类
public <T> T createByClazzName(Class<? extends T> clazz){
T obj = null;
try {
obj = (T) Class.forName(clazz.getName()).newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
}
}
这样做的好处是,当有新的产品加入时,不用修改工厂类,在调用的时候,采用如下方式即可获取对象!
代码语言:javascript复制Product product = new SimpleFactory().create("类名.class");
三、工厂方法模式
和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂。
- 创建一个工厂接口
public interface FactoryProduct {
Product create();
}
- 创建实现接口的实体类
public class ConcreateFactoryA implements FactoryProduct{
@Override
public Product create() {
return new ConcreateProductA();
}
}
代码语言:javascript复制public class ConcreateFactoryB implements FactoryProduct{
@Override
public Product create() {
return new ConcreateProductB();
}
}
- 编写客户端测试类,使用该工厂,通过传递类型信息来获取实体类的对象
public class FactoryPatternDemo {
public static void main(String[] args) {
//获取 productA 的对象
Product productA = new ConcreateFactoryA().create();
//调用 productA 的 operation1、operation2 方法
productA.operation1();
productA.operation2();
//获取 productB 的对象
Product productA = new ConcreateFactoryB().create();
//调用 productB 的 operation1、operation2 方法
productB.operation1();
productB.operation2();
}
}
- 执行程序,输出结果:
产品A,执行任务1
产品A,执行任务2
产品B,执行任务1
产品B,执行任务2
四、抽象工厂模式
抽象工厂模式主要是应对产品族概念提出来的。提供一个创建一系列相关或相互依赖的对象。
- 为形状创建一个接口
public interface Shape {
void draw();
}
- 创建实现接口的实体类
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
代码语言:javascript复制public class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
代码语言:javascript复制public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
- 为颜色创建一个接口
public interface Color {
void fill();
}
- 创建实现接口的实体类
public class Red implements Color {
@Override
public void fill() {
System.out.println("Inside Red::fill() method.");
}
}
代码语言:javascript复制public class Green implements Color {
@Override
public void fill() {
System.out.println("Inside Green::fill() method.");
}
}
代码语言:javascript复制public class Blue implements Color {
@Override
public void fill() {
System.out.println("Inside Blue::fill() method.");
}
}
- 为 Color 和 Shape 对象创建抽象类来获取工厂
public abstract class AbstractFactory {
public abstract Color getColor(String color);
public abstract Shape getShape(String shape) ;
}
- 创建扩展了 AbstractFactory 的工厂类,基于给定的信息生成实体类的对象
public class ShapeFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
@Override
public Color getColor(String color) {
return null;
}
}
代码语言:javascript复制public class ColorFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
return null;
}
@Override
public Color getColor(String color) {
if(color == null){
return null;
}
if(color.equalsIgnoreCase("RED")){
return new Red();
} else if(color.equalsIgnoreCase("GREEN")){
return new Green();
} else if(color.equalsIgnoreCase("BLUE")){
return new Blue();
}
return null;
}
}
- 创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
} else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}
- 使用 FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象
public class AbstractFactoryPatternDemo {
public static void main(String[] args) {
//获取形状工厂
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
//获取形状为 Circle 的对象
Shape shape1 = shapeFactory.getShape("CIRCLE");
//调用 Circle 的 draw 方法
shape1.draw();
//获取形状为 Rectangle 的对象
Shape shape2 = shapeFactory.getShape("RECTANGLE");
//调用 Rectangle 的 draw 方法
shape2.draw();
//获取形状为 Square 的对象
Shape shape3 = shapeFactory.getShape("SQUARE");
//调用 Square 的 draw 方法
shape3.draw();
//获取颜色工厂
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
//获取颜色为 Red 的对象
Color color1 = colorFactory.getColor("RED");
//调用 Red 的 fill 方法
color1.fill();
//获取颜色为 Green 的对象
Color color2 = colorFactory.getColor("Green");
//调用 Green 的 fill 方法
color2.fill();
//获取颜色为 Blue 的对象
Color color3 = colorFactory.getColor("BLUE");
//调用 Blue 的 fill 方法
color3.fill();
}
}
- 执行程序,输出结果:
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
Inside Red::fill() method.
Inside Green::fill() method.
Inside Blue::fill() method.
五、应用
工厂模式在实际开发中使用非常频繁,例如 JDK 中的日历操作,在国际化的时候,获取本地语言就用到简单工厂模式。
写一个获取测试,如下:
代码语言:javascript复制public static void main(String[] args) {
//获取日历操作类
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
// 取月份要加1
int month = calendar.get(Calendar.MONTH) 1;
int day = calendar.get(Calendar.DAY_OF_MONTH);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
int seconds = calendar.get(Calendar.SECOND);
// 1-7分别代表 -- 星期日,星期一,星期二,星期三,星期四,星期五,星期六
int week = calendar.get(calendar.DAY_OF_WEEK);
// 年-月-日
System.out.println("year = " year);
System.out.println("month = " month);
System.out.println("day = " day);
//时-分-秒
System.out.println("hour = " hour);
System.out.println("minute = " minute);
System.out.println("seconds = " seconds);
// 星期
System.out.println("week = " week);
}
进入getInstance()
方法,在获取日历类型的时候,内容如下:
六、小结
工厂模式中,重要的是工厂类,而不是产品类。产品类可以是多种形式,多层继承或者是单个类都是可以的。
但要明确的,工厂模式的接口只会返回一种类型的实例,这是在设计产品类的时候需要注意的,最好是有父类或者共同实现的接口。
上面介绍的三种工厂模式有各自的应用场景,实际应用时能解决问题满足需求即可!
七、参考
1、菜鸟教程 - 工厂模式
2、博客园 - alpha_panda - 设计模式之工厂模