工厂模式设计IOC容器


IOC容器的底层实现其实就是利用工厂设计模式。接下来我们通过工厂设计模式模拟一个小型的IOC容器,让大家对IOC的底层原理更加清晰些。

一、搭建案例程序

1)CustomerDao接口:

package com.yiidian.dao;

public interface CustomerDao {

	public void save();
	
}

2)CustomerDaoMySQLImpl:(模拟MySQL版本的Dao实现)

package com.yiidian.dao.impl;

import com.yiidian.dao.CustomerDao;
/**
 * 
 * @author http://www.yiidian.com
 *
 */
public class CustomerDaoMySQLImpl implements CustomerDao {

	@Override
	public void save() {
		System.out.println("把客户数据保存到mysql数据");
	}

}

3)CustomerService接口:
 

package com.yiidian.service;
/**
 * 
 * @author http://www.yiidian.com
 *
 */
public interface CustomerService {

	public void save();
}

4)CustomerServiceImpl实现类:

package com.yiidian.service.impl;

import com.yiidian.dao.CustomerDao;
import com.yiidian.dao.impl.CustomerDaoImpl;
import com.yiidian.service.CustomerService;
/**
 * 
 * @author http://www.yiidian.com
 *
 */
public class CustomerServiceImpl implements CustomerService {
	//1.传统方法,直接new对象.
	private CustomerDao customerDao = new CustomerDaoImpl();

	@Override
	public void save() {
		customerDao.save();
	}

}

5)ActionDemo类(模拟Struts2的Action):

package com.yiidian.web;

import com.yiidian.service.CustomerService;
import com.yiidian.service.impl.CustomerServiceImpl;
/**
 * 
 * @author http://www.yiidian.com
 *
 */
public class ActionDemo {

	public static void main(String[] args) {
		//传统方式调用业务,直接new对象
		CustomerService customerService = new CustomerServiceImpl();
		customerService.save();
	}
}

6)运行ActionDemo的main方法,执行结果为:

二、扩展程序,发现问题

1)给CustomerDao接口添加多一个实现类,CustomerDaoOracleImpl(模拟Oracle的Dao实现):

package com.yiidian.dao.impl;

import com.yiidian.dao.CustomerDao;
/**
 * 
 * @author http://www.yiidian.com
 *
 */
public class CustomerDaoOracleImpl implements CustomerDao {

	@Override
	public void save() {
		System.out.println("保存客户数据保存Oracle");
	}

}

2)这时我们需要在CustomerServiceImpl类中调用CustomerDaoOracleImpl的方法,需要手动修改代码实现:

package com.yiidian.service.impl;

import com.yiidian.dao.CustomerDao;
import com.yiidian.dao.impl.CustomerDaoOracleImpl;
import com.yiidian.service.CustomerService;
/**
 * 
 * @author http://www.yiidian.com
 *
 */
public class CustomerServiceImpl implements CustomerService {
	//1.传统方法,直接new对象.
	//private CustomerDao customerDao = new CustomerDaoMySQLImpl();
	private CustomerDao customerDao = new CustomerDaoOracleImpl(); //(弊端:耦合性太高,修改源代码)

	@Override
	public void save() {
		customerDao.save();
	}

}

3)运行ActionDemo,查看结果:

总结问题:我们每次为CustomerDao接口扩展了实现类,业务层需要修改代码才可以实现切换具体的实现类,这种做法为“硬编码”方式,扩展性不好!接下来开始引用工厂设计模式改造程序。

三、利用工厂设计模式,改造程序

1)编写一个BeanFactory类,用于读取配置文件,创建程序需要的对象:

package com.yiidian.ioc;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * 创建对象的工厂(模拟简单IOC容器)
 * @author http://www.yiidian.com
 *
 */
public class BeanFactory {
	
	/**
	 * 初始化beans.properties文件
	 */
	private static Properties props = new Properties();
	static{
		InputStream in = BeanFactory.class.getResourceAsStream("/beans.properties");
		try {
			props.load(in);
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("加载beans.properties文件失败");
		}
	}

	/**
	 * 从工厂获取一个对象
	 * @return
	 */
	public static Object getBean(String name){
		//根据name创建不同的对象
		//1.通过name在properties文件找到类名称
		String className = props.getProperty(name);
		//2.通过反射构造类的对象
		try {
			return Class.forName(className).newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}

2)在src目录编写beans.properties配置文件:

beans.properties:

customerDao=com.yiidian.dao.impl.CustomerDaoMySQLImpl

3)改造CustomerServiceImpl类:

/**
 * 
 * @author http://www.yiidian.com
 *
 */
public class CustomerServiceImpl implements CustomerService {
	//1.传统方法,直接new对象.
	//private CustomerDao customerDao = new CustomerDaoMySQLImpl();
	//private CustomerDao customerDao = new CustomerDaoOracleImpl(); //(弊端:耦合性太高,修改源代码)
	
	//2.IOC容器
	private CustomerDao customerDao = (CustomerDao) BeanFactory.getBean("customerDao");

	@Override
	public void save() {
		customerDao.save();
	}

}

4)运行ActionDemo,这时可以调用Dao程序,这时如果需求切换到CustomerDaoOracleImpl,只需要修改beans.properties,改为:

customerDao=com.yiidian.dao.impl.CustomerDaoOracleImpl

再次运行ActionDemo,可以看到已经成功切换到Oracle的Dao实现啦!

 

到此为止,BeanFactory就是一个小型的IOC容器,可以创建我们程序中需要的一些对象。事实上,Spring的IOC容器的底层就是类似BeanFactory的原理

 

源码下载: http://pan.baidu.com/s/1geJrQCF