引:在面向对象的思维中,万物皆对象,就像有女蜗造人,我们也可以用工厂方法模式造对象。
定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类。——创造类
工厂方法模式的通用类图如下:
下面是一个比较实用的通用源码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57// 抽象产品类
public abstract class Product {
// 产品类的公共方法
public void method1() {
// 业务逻辑处理
}
//抽象方法
public abstract void method2();
}
// 具体产品类
public class ContreteProduct1 extends Product {
public void method2() {
// 业务逻辑处理
}
}
public class ContreteProduct2 extends Product {
public void method2() {
// 业务逻辑处理
}
}
// 抽象工厂类
public abstract class Creator {
/*
* 创建一个产品对象,其输入参数类型可以自行设置
* 通常为String, Enum, Class等,当然也可以为空
*/
public abstract <T extends Product> T createProduct(Class<T> c);
}
// 具体工厂类
public class ContreteCreator extends Creator {
public abstract <T extends Product> T createProduct(Class<T> c) {
Product product = null;
try {
product = (Product) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
// 异常处理
}
return (T)product;
}
}
// 场景类
public class Client {
public static void main(String[] args) {
Creator creator = new ContreteCreate();
Product product = creator.createProduct(ContreteProduct1.class);
/*
* 继续业务处理
*/
}
}
应用
优点
- 良好的封装性,代码结构清晰。
- 扩展性非常优秀,要增加一个新的产品,只要实现Product接口。
- 屏闭产品类。只要关心产品的接口即可,例如换数据库只要换驱动即可。
- 符合迪米特法则(只要知道产品的接口即可);符合依赖倒置原则(值依赖产品的抽象类即可);符合里氏替换原则(使用产品子类可以替换产品父类)。
使用场景
- 只要使用new的地方都可以使用工厂方法模式,但是要考虑代码的复杂度。
- 需要灵活的,可扩展的框架时(有多个产品可选且可以随时增加时),可以考虑工厂方法模式。
- 工厂方法模式可以用在异构项目中。
- 可以使用在测试驱动开发的框架下。
工厂方法模式的扩展
缩小为简单工厂模式
实质是去掉了创造者接口,使具体创造者直接依赖产品接口。缺点是扩展比较困难,不符合开闭原则。
升级为多个工厂类
实质是为了结构清晰,我们为每个产品定义一个创造者,然后由调用者自己去选择与那个工厂方法关联。
替代单例模式
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public class SingletonFactory {
private static Singleton singleton;
static {
try {
Class c1 = Class.forName(Singleton.class.getName());
// 获得无参构造
Constructor constructor = c1.getDeclaredConstructor();
//设置无参构造是可访问的
constructor.setAccessible(true);
// 产生一个实例对象
singleton = (Singleton) constructor.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Singleton getSingleton() {
return singleton;
}
}延迟初始化
所谓延迟初始化即一个对象被消费完毕后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。其实质,是利用一个Map保存创造过的对象,如果在Map容器已经有的对象,则直接取出返回;如果没有,则根据需要的类型产生一个对象并放入到Map容器中,以方便下次调用。
最佳实践
孰能生巧,熟练掌握该设计模式,多思考工厂方法如和应用,而且工厂方法模式可以与其他模式混合使用,变化出无穷的优秀设计。
参考
- 《设计模式之禅》