概念
工厂模式用于方便快捷地创建对象,而不用关心这个对象是如何创建的
工厂模式使用一个工厂方法代替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(); } }
运行结果: