工厂模式 详解
工厂模式严格意义来说是三种模式(简单工厂模式,工厂方法模式,抽象工厂模式)
简单工厂模式
本质
选择实现
功能:工厂嘛,就是用来创造东西的。在java里面,通常情况下用来创造接口的,但是也可以创造抽象类,甚至是一个具体的类实例。
静态工厂
使用简单工厂的时候,通常不用创建简单工厂类的类实例,没有创建实例的必要。因此可以把简单工厂类实现成一个工具类,直接使用静态方法就可以了。也就是说简单工厂方法通常是静态的,所有也被称为静态工厂。如果要防止客户端无谓的创造简单工厂实例,还可以把简单工厂的构造方法私有化。
万能工厂
一个简单工厂可以包含很多可以用来构造东西的方法,这些方法可以创建不同的接口,抽象类或者是类实例。一个简单工厂理论上是可以构造任何东西,所有又称之为“万能工厂”。
简单工厂创建实例的范围
虽然理论上讲,简单工厂什么都可以创建,但对于简单工厂创建实例的范围,通常不要太大,建议控制在一个独立的组件级别或者一个模块级别,也就是一个组件或者模块的简单工厂。否则这个简单工厂的职责不明,有点大杂烩的感觉。
简单工厂的命名建议
类名称:模块名称+Factory
方法名称:“get+接口名称”或者“create+接口名称”。
简单工厂实现
简单工厂的方法大多是用来创建接口的,但仔细分析就会发现,真正实现功能的是具体实现类,这些实现类是以及做好的,并不是真的需要简单工厂来创建,简单工厂的方法无外乎就是:实现了选择一个合适的实现类来使用。
所有简单工厂方法的内部主要实现的功能是:”选择合适的实现类“来创建实例对象。
要实现选择,那么就需要选择的条件或者选择的参数,条件和参数的来源就有以下几种:
来源于客户段,由Client来传入参数
来源于配置文件,从配置文件获取用于判断的值
来源于程序运行期的某个值,比如从缓存中获取某个运行期的值
实现代码
public class Factory{
public static Api createApi(int type){
Api api = null;
if(type==1){
api = new Impl();
}else if(type==2){
api = new Impl2();
}else if(type==3){
api = new Impl3();
}
return api;
}
}
这种方式每次新增一个实现类都要修改工厂类的实现,肯定不是一个好的实现方式。现在想要新增一个不要修改工厂类,需要怎么做?
一个方案是使用配置文件,当有了新的实现类后只要在配置文件中配置上新的实现类即可。在简单工厂方法里面可以使用反射,也可以使用IOC/DI(控制反转/依赖注入)来实现。
实现代码
首先在配置文件中配置实现类,配置文件这里用简单的properties文件,一般开发中用XML文件。定义一个名称为“FactoryTest.properties”的配置文件,放在Factory同一个包下面,
文件内容:表述实现类名称(String)=实现类类全名(String)
工厂类实现代码
public class Factory {
public static Api getApi(String name) {
Properties p = new Properties();
InputStream in = null;
try {
in = Factory.class.getResourceAsStream("FactoryTest.properties");
p.load(in);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Api api = null;
try {
api = (Api)Class.forName(p.getProperty(name)).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return api;
}
public static void main(String[] args) {
Factory.getApi(表述实现类名称).study();
}
}
简单工厂优点
帮助封装
简单工厂虽然简单,但非常友好的帮助我们实现了组件的封装,然后让组件外部能真正的面向接口编程。
解耦
通过简单工厂,实现了客户端和具体实现类的解耦。
如上,客户端根本不知道具体是由谁来实现,也不知具体是如何实现的,客户端只是通过工厂获取它需要的接口对象。
工厂方法模式
本质
延迟到子类来选择实现
定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method 使一个类的实例化延迟到其子类。
解决思路
工厂方法模式的解决思路很有意思,那就是不解决,采取无为而治的方式:不是需要接口对象吗,那就定义一个方法来创建;可是事实上它自己是不知道怎么创建这个接口对象的,没关系,定义成抽象方法就可以了,自己实现不了就让子类去实现,这样这个对象本身就可以只是面向接口编程,而无需关心到底如何创建接口对象了。
实现代码
//工厂方法所创建的对象的接口
public interface Api {
//定义Api的属性和方法
}
//具体的Api对象
public class ApiImp implements Api {
//实现Api要求的方法
}
//创建器,声明工厂方法
public abstract class Creator{
protected abstract Api factoryMethod();
public void someOperation(){
Api api = factoryMethod();
}
}
//具体创建器实现对象
public class ConcreteCreator extends Creator {
protected abstract Api factoryMethod(){
return new ApiImpl();
}
}
抽象工厂模式
本质
选择产品簇的实现
定义
提供一个创建一系列相关或相互依赖的接口,而无需指定它们具体的类。
用抽象工厂模式解决问题的思路
两个问题点:一个是只知道所需要的一系列对象的接口,而不知具体实现,或者不知道具体使用哪一个实现;另外一个是这一系列对象是相关或相互依赖的,也就是说既要创建接口的对象,还有约束它们之间的关系。
注意:简单工厂模式和方法工厂模式关注的是单个产品对象的创建。
事例代码:
/**
* 抽象工厂接口,声明创建抽象产品对象的操作
* @author Administrator
*
*/
public interface AbstractFactory {
/**
* 创建抽象产品A对象
*/
public AbstractProductA CreateProductA();
/**
* 创建抽象产品B对象
*/
public AbstractProductB CreateProductB();
}
省略产品A和产品B的具体实现代码
/**
* 具体的工厂实现对象,实现创建具体的产品对象的操作
**/
public class ConcreteFactory1 implements AbstractFactory {
public AbstractProductA createProductA(){
return new ProductA1();
}
public AbstractProductB createProductB(){
return new ProductB1();
}
}
/**
* 具体的工厂实现对象,实现创建具体的产品对象的操作
**/
public class ConcreteFactory2 implements AbstractFactory {
public AbstractProductA createProductA(){
return new ProductA2();
}
public AbstractProductB createProductB(){
return new ProductB2();
}
}
客户端:
public class Client{
public static void main(String[] agrs){
//创建抽象工厂对象
AbstractFactory af = new ConcreteFactory1();
//通过工厂来获取一系列的对象,如产品A和产品B
af.createProductA();
af.createProductB();
}
}
实现抽象工厂模式的灵活性,可以和简单工厂模式组合(具体的创建对象用简单工厂模式来做)。