概念
工厂模式用于方便快捷地创建对象,而不用关心这个对象是如何创建的
工厂模式使用一个工厂方法代替new关键字来实例化对象
工厂模式分简单工厂模式、工厂方法模式和抽象工厂模式
简单工厂模式是工厂方法模式的一个特例,抽象工厂模式是工厂方法模式的扩展
工厂(Factory)定义一个接口来创建对象,但是让子类来决定哪些对象需要被实例化
工厂方法模式类图:
抽象工厂模式类图:
作用
降低了对象类和使用类的耦合性,当对象类发生变化时,使用类并不需要作出过多的修改
比如一个对象的构造方法要求传入多个参数,当我们使用new来构造实例时就要把所有参数传进去,而一旦这个类的构造方法所需参数发生了改变,我们就必须在每一个使用new的语句中同步修改,这无疑是十分繁琐且容易出错的。如果使用工厂模式,我们仅需修改create方法这一个位置就可以了
使用场景
有一组类似但不是同一个类的对象需要创建
在编码时不能预见需要创建哪种类的实例(动态创建)
例子
我们日常生活中可能会用到很多不同颜色的笔,比如写一篇笔记的时候,使用黑笔写内容,使用蓝笔写注释,使用红笔来突出重点,而记笔记的纸也可以有很多种,比如白纸、单线纸、双线纸等等,如果用代码表示的话,就需要new很多个不同的类的实例对象,这样做是不方便也不利于维护的。那么我们就可以使用工厂模式来为这些笔和纸构建实例对象。
不同的笔其功能都是一样的,都是用来写字,我们就可以创建一个笔的接口,并声明一个写字的方法,所有笔的类都要实现这个接口,在Factory类的Create方法种返回这个接口的对象,就是一个具体的笔的实例了
代码示例
//笔的接口
public interface IPen {
void writeText();
}
//笔的工厂类
public class PenFactory {
public static final int RED_PEN = 0;
public static final int BLACK_PEN = 1;
public static final int BLUE_PEN = 2;
/**
* 使用反射机制来加载产品类
*
* @param key
* @return
*/
static IPen Create(String key) {
PropertiesReader reader = new PropertiesReader();
Map<String, String> map = reader.getProperties();
String className = map.get(key);
if (className == null) {
throw new NullPointerException("没有相应的类,key:" + key);
}
try {
return (IPen) Class.forName(className).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* 使用颜色代码判断要生产什么笔
*
* @param colorCode
* @return
*/
static IPen Create(int colorCode) {
switch (colorCode) {
case RED_PEN:
return new RedPen();
case BLACK_PEN:
return new BlackPen();
case BLUE_PEN:
return new BluePen();
default:
throw new NullPointerException("没有颜色值为" + colorCode + "的笔");
}
}
}
上面的代码中有两种Create方法,一种是使用int类型作为笔的代码,这种写法较为简单,但是当我们的产品类有很多时,使用这种方法就要声明同样多的int值,这样就变得很不方便了,因此我们可以使用另一种类加载的方式。
类加载是使用Java反射机制实现的,通过Class类的forName方法找出一个类,并使用newInstance方法创建一个实例。
在forName(String className)中要传入完整的类名(包名+类名称),这里是使用了一个映射(propertites文件),用指定字符串映射了相应的完整类名。
//黑笔,其他笔也是一样的写法
public class BlackPen implements IPen {
@Override
public void writeText() {
System.out.println("使用黑笔写字");
}
}
//测试类
public class Test {
public static void main(String[] args) {
//使用映射
IPen redPen = PenFactory.Create("red");
redPen.writeText();
IPen bluePen = PenFactory.Create("blue");
bluePen.writeText();
//使用笔的代码
IPen blackPen = PenFactory.Create(PenFactory.BLACK_PEN);
blackPen.writeText();
IPen none = PenFactory.Create(3);
none.writeText();
}
}
运行结果: