设计模式演绎-工厂方法模式

定义

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory method lets a class defer instantiation to subclasses.

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其他类。

通用类图

工厂方法模式

  • Product 是抽象产品类,ConcreteProduct是对Product类的具体实现
  • Creator 是抽象创建类,也就是抽象工厂,ConcreteCreator是实现工厂,如何创建产品类就是在ConcreteCreator类中实现。

通用代码

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();
}
/* 具体产品类1 */
public class ConcreteProduct1 extends Product {
public void method2() {
//实现业务逻辑
}
}
/* 具体产品类2 */
public class ConcreteProduct1 extends Product {
public void method2() {
//实现业务逻辑
}
}
/* 抽象工厂类 */
public abstract class Creator {
/*
* 抽象方法:在实现类中必须实现
* 作用是创建一个产品类
* 出参:<T extends Product>说明返回值可以是任何继承了Product的对象
* 入参:Class<T> c 根据实际情况设置
*/
public abstract <T extends Product> T createProduct(Class<T> c);
}
/* 具体工厂类 */
public class ConcreteCreator {
public <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 ConcreteCreator(); //获取一个工厂类示例
//使用工厂类创建了ConcreteProduct1类的一个实例
Product product = creator.createProduct(ConcreteProduct1.class);
// 继续处理业务逻辑
}
}

一个例子

工厂方法模式示例-GitHub

工厂方法模式的优点

  • 良好的封装性,代码结构清晰,屏蔽产品类。使用者只要说明自己想要什么就可以了,具体怎么创建,它不用去管,降低了代码的耦合。符合迪米特法则。
  • 良好的扩展性。在增加产品类的情况下,只要修改具体的工厂类或者扩展一个产品类就可以完成。

工厂方法模式的使用场景

在所有需要new一个对象的时候,都可以采用工厂方法模式来替代new。但是滥用会带来代码的复杂度。用不用取决于这一块在业务上需不需要灵活、可扩展。比如一个类有3个扩展类,我们需要根据传入条件去初始化对应的扩展类,这种场景就适合用工厂方法模式。调用者不用管具体的扩展类,只要知道抽象类。工厂方法根据传入的参数去决定创建哪个扩展类的实例给它。而且以后增加第4个扩展类,也非常方便。屏蔽变化,完美扩展。

工厂方法模式的简化

在通用类图中,我们去掉抽象工厂类,然后把实现工厂类的创建产品的方法转为静态方法。整个工厂方法模式就大大简化了。具体编码中,我们采用这种简单工厂模式比较多。简单是它的优点,缺点是不符合开闭原则。