什么是工厂方法模式?
工厂方法模式是一种创建型设计模式。
工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中,核心工厂类不再负责产品创建,这样核心类成为一个抽象工厂的角色,仅负责具体工厂子类必须实现的接口,这样做的好处是系统可以在不修改具体工厂角色的情况下,添加新产品。
工厂模式在实际开发中应用很广,比如Spring的Bean工厂。举个例子,如果在一个系统中,我们需要连接多种种类的数据库,在系统架构设计时,我们通常把数据库连接这部分分离开来。而在获取数据库连接时,我们可以通过工厂方法模式获取相应的数据库连接,其实,Spring也是用这种方法进行连接管理。
核心结构
- Product。抽象产品,它定义了产品的接口,是具体产品角色的公共父类。
- ConcreteProduct。具体产品,它实现了抽象产品接口,具体产品由具体工厂创建,一一对应。
- Factory。抽象工厂,它定义了工厂方法,并返回一个产品,是工厂方法模式的核心,所有的具体工厂方法都必须实现抽象工厂,抽象工厂既可以是接口,又可以是抽象类。
- ConcreteFactory。具体工厂,它是抽象工厂的子类,实现了抽象工厂方法中定义的工厂方法,调用者可以调用这个方法来获取产品实例。
类图展示
代码分析
在工厂方法模式中,我们将对简单工厂模式的示例进行优化。
首先我们还是创建抽象产品角色——推送人群:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 工厂模式——抽象产品
*/
public abstract class Group {
public void before() {
System.out.println("Selecting group...");
}
public void after() {
System.out.println("done");
}
public abstract void select();
}
接着,我们创建具体产品角色——还是一样的配方,还是一样的味道:
青少年人群:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 工厂模式——具体产品
*/
public class TeenageGroup extends Group {
@Override
public void select() {
System.out.println("focus on teenagers");
}
}
成年人群:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 工厂模式——具体产品
*/
public class AdultGroup extends Group {
@Override
public void select() {
System.out.println("focus on adult");
}
}
年长人群:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 工厂模式——具体产品
*/
public class ElderGroup extends Group {
@Override
public void select() {
System.out.println("focus on elder");
}
}
接下来写工厂方法模式的核心。
我们需要定义一个抽象工厂:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 工厂模式——抽象工厂
*/
public abstract class GroupFactory {
public abstract Group getGroup();
}
根据不同的具体产品,我们将为其创建专属生产工厂。
青少年人群生产工厂:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 工厂模式——具体工厂
*/
public class TeenageGroupFactory extends GroupFactory {
@Override
public Group getGroup() {
return new TeenageGroup();
}
}
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 工厂模式——具体工厂
*/
public class AdultGroupFactory extends GroupFactory {
@Override
public Group getGroup() {
return new AdultGroup();
}
}
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 工厂模式——具体工厂
*/
public class ElderGroupFactory extends GroupFactory {
@Override
public Group getGroup() {
return new ElderGroup();
}
}
完活,上测试用例:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 工厂模式测试
*/
public class FactoryTest {
public static void main(String[] args) {
factoryTest();
}
private static void factoryTest() {
try {
GroupFactory factory = null;
Group group = null;
factory = new TeenageGroupFactory();
group = factory.getGroup();
group.before();
group.select();
group.after();
factory = new AdultGroupFactory();
group = factory.getGroup();
group.before();
group.select();
group.after();
factory = new ElderGroupFactory();
group = factory.getGroup();
group.before();
group.select();
group.after();
} catch (Exception e) {
e.printStackTrace();
}
}
}
模式总结
优点
- 外部调用方无需关心产品生产细节,甚至无需知道产品类名,只需知道生产产品的具体工厂角色即可。
- 新增产品无需修改原有代码,仅仅添加新增具体产品角色和对应的具体工厂角色即可。
- 产品角色和工厂角色的多态性设计是工厂方法模式的关键,它能够个性化生产产品对象,创建对象的细节完全封装在具体工厂内部。
缺点
- 添加新产品时,需要添加新的产品角色和新的生产工厂,系统中类的个数将成对增加,提高了系统的复杂性。
- 由于大量使用了多态特性,增加了系统的抽象性和理解难度,在一定程度上增加了业务实现难度。
适用场景
- 外部调用不关心对象的创建细节,仅需获取对象。