最近在学习spring源码,发现在IoC容器初始化的时候创建各种bean,然后在代码中看到各种beanFactory和factoryBean,很显然spring容器在创建bean的过程是使用了工厂设计模式,那么正好总结一下工厂设计模式。
工厂模式分为简单工厂、工厂方法、抽象工厂三种
一、简单工厂
简单工厂的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类
spring中创建bean的过程中无论是通过xml配置还是通过配置类进行创建bean,大部分都是通过简单工厂来进行创建的。比如说当容器拿到了bean的beanname和class类型后,动态的通过反射创建具体的某个对象,最后将创建的对象放到Map中。那么为什么要使用简单工厂、简单工厂有什么优点、以及如何使用简单工厂呢?我们学习设计模式肯定要知道为什么要使用他,在什么场景使用它,我们创建对象的时候为什么不使用new对象呢,为什么要使用工厂模式和构造者模式呢,这肯定是有原因的
场景:现在我们来生产车。分别能生产宝马、奔驰、大众,正常情况下我们要使用创建这三种车的时候,直接new一个对象就行,然后调用其他的方法。代码如下所示
Car.java
package factory;
public interface Car {
void run();
}
BMWCar .java
package factory;
public class BMWCar implements Car{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("bmw car running...");
}
}
BenChiCar .java
package factory;
public class BenChiCar implements Car{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("benchi car running");
}
}
DaZhongCar .java
package factory;
public class DaZhongCar implements Car{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("dazhong car running...");
}
}
SimpleFactoryTest .java
package factory;
public class SimpleFactoryTest {
public static void main(String[] args) {
Car bmw = new BMWCar();
Car benchi = new BenChiCar();
Car dazhong = new DaZhongCar();
bmw.run();
benchi.run();
dazhong.run();
}
}
上述代码非常简单,并且也没问题,完全可以使用,那么现在问题来了
1,现在随着扩展,有这样的一个要求,就是生产汽车的过程中,还需要做一些其他的操作,比如给轮胎打气、检测发动机、检测安全气囊...等等非常多且比较复杂的工作,虽然有些工作,我们可以放在构造方法中去完成,但是有些操作不适合放在构造方法中去执行的,那么怎么办?每次创建对象的时候都需要操作这些方法?只在一个地方构造对象还好,如果是在n多个地方都创建该对象呢?必然会导致代码的重复。
2、现在业务发生了更改,我们现在不生产奔驰,而是生产奔奔,那么需要将以前生产奔驰的地方全部改成生产奔奔,怎么修改?所有new BenchiCar()的地方全部改成new BenbenCar()?
好了那么这个时候可以使用我们的简单工厂方法
创建工厂类解决上述两个问题
CarFactory .java
package factory;
public class CarFactory {
public Car getCar(String carName) {
Car car = null;
if(carName.equals("bmw")) {
car = new BMWCar();
/*
*这里可以统一执行一些操作 ,比如给轮胎打气,给电瓶充电、检测安全气囊等等
*/
}else if(carName.equals("benchi")) {
//car = new BenChiCar();
//比如现在要将以前所有的奔驰车全部改成奔奔车,只需要将上述的car = new BenChiCar();改成如下
car = new BenBenCar();
/*
*这里可以统一执行一些操作 ,比如给轮胎打气,给电瓶充电、检测安全气囊等等
*/
}else if(carName.equals("dazhong")) {
car = new DaZhongCar();
/*
*这里可以统一执行一些操作 ,比如给轮胎打气,给电瓶充电、检测安全气囊等等
*/
}
return car;
}
}
SimpleFactoryTest .java
package factory;
public class SimpleFactoryTest {
public static void main(String[] args) {
CarFactory carFactory = new CarFactory();
Car bmw = carFactory.getCar("bmw");
Car benchi = carFactory.getCar("benchi");
Car dazhong = carFactory.getCar("dazhong");
bmw.run();
benchi.run();
dazhong.run();
}
}
是不是觉得很ok呢?不用牵一发而动全身,其实spring中beanfactory创建bean就是通过上述的简单工厂进行创建,只是他底层通过反射的方式创建对象。简单工厂就是让创建者屏蔽创建的过程,只管使用就行。是不是所有创建对象的方式都能通过上面的方式去创建呢,假如现在有随着业务的扩展,我需要创建的车越来越多了,新增了丰田、荣威、比亚迪,那怎么办?难道要每一次都需要去修改这个工厂方法中的getCar()方法吗?这显然不符合设计模式中的开闭原则(对修改关闭、对扩展开放),那怎么办?下面工厂方法解决了这个问题
二、工厂方法
根据上面的问题描述,直接上代码吧
上面的汽车的接口Car和具体的类我就不重复贴代码了
CarFactory .java
package factorymethod;
public interface CarFactory {
Car getCar();
}
BMWCarFactory .java
package factorymethod;
public class BMWCarFactory implements CarFactory{
@Override
public Car getCar() {
// TODO Auto-generated method stub
return new BMWCar();
}
}
FengtianCarFactory .java
package factorymethod;
public class FengtianCarFactory implements CarFactory{
@Override
public Car getCar() {
// TODO Auto-generated method stub
return new FengTianCar();
}
}
FactoryMethodTest .java
package factorymethod;
public class FactoryMethodTest {
public static void main(String[] args) {
CarFactory benbenFactory = new BenBenCarFactory();
Car benben = benbenFactory.getCar();
benben.run();
CarFactory fengtianFactory = new FengtianCarFactory();
Car fengtian = fengtianFactory.getCar();
fengtian.run();
}
}
这个时候如果我们需要新增汽车品牌的时候,只需要新建相应的工厂,然后将创建对象的过程延迟到子类(实现类)具体实现,接口只负责定义规则,这种设计就是符合开闭原则,对修改关闭,对扩展开放,spring中FactoryBean就是这种设计模式,当FactoryBean的getObject就是通过他的实现类具体的去生产某个bean,所以FactoryBean.getObject并不是返回一个Factorybean的对象,而是返回由Factorybean创建的相应的bean,就好比我们上面FenttianFactory.getcar返回的不是工厂,而是返回对应的fengtian car
抽象工厂留着下次再讲吧,如有问题,欢迎指正,大家一起讨论