面向对象程序设计(Object Oriented Programming,OOP)是当今程序设计的主流,它很好地实现了软件的重用性和扩展性。
采用OOP设计的系统是由很多个对象组成的,对象和对象之间会构成依赖关系,这时需要有一个专门的模块来管理这些对象的创建和它们之间的依赖关系,否则这些对象会紧紧地耦合在一起,使系统变得难以维护和扩展。这个专门的模块就叫对象管理器,简称容器。
容器负责创建对象,提供查找对象的服务(也就是管理依赖关系),管理对象的生命周期等等。
运行在容器中的对象也称为组件,它们必须遵循容器定义的规范。
在JavaEE开发中,我们通常定义DAO层和Service层。先看以下代码:
interface Dao{
public void daoMethod();
}
interface Service{
public void serviceMethod();
}
class DaoImplA implements Dao{
public void daoMethod() {
System.out.println("DaoImplA.daoMethod");
}
}
class DaoImplB implements Dao{
public void daoMethod() {
System.out.println("DaoImplB.daoMethod");
}
}
class ServiceImpl implements Service{
private Dao dao = new DaoImplA();
public void serviceMethod() {
dao.daoMethod();
}
}
UML类图如下:
我们可以看到,ServiceImpl不但依赖Dao层的接口,还依赖其实现,显然违背了OOP的“依赖接口,不依赖实现”的原则。
下面我们使用容器将依赖实现的那根线消除。
容器类:
package com.xs;
import java.util.HashMap;
import java.util.Map;
public class Container {
private static Map<String, Object> components;
private Container(){}
/**
* 初始化容器
*/
public static synchronized void init(){
if (components == null) {
components = new HashMap<String, Object>();
Dao daoA = new DaoImplA();
components.put("daoA", daoA);
Service service = new ServiceImpl();
components.put("service", service);
}
}
/**
* 查找组件
* @param id
* @return
*/
public static Object getComponent(String id){
return components.get(id);
}
}
修改ServiceImpl类:
class ServiceImpl implements Service{
private Dao dao = (Dao) Container.getComponent("daoA");
public void serviceMethod() {
dao.daoMethod();
}
}
问题:如果在容器中,service比Dao先实例化,则service得到的Dao为null,执行dao.daoMethod方法的时候会报空指针异常,解决的办法是在serviceMethod方法中查找Dao组件,但这样的话,service中每个需要用到Dao的地方,都要先查找Dao,显得繁琐。
public static void main(String[] args) {
Container.init();
Service service = (Service) Container.getComponent("service");
service.serviceMethod();
}
此时的UML类图如下:
此时的service层不再依赖Dao层的实现,而把这种对实现的依赖交给了容器,但是我们却发现,serviceImpl依赖了Container容器类,使得组件不能脱离容器独立存在,显然,这是一种“侵入式”的管理。如何让组件不依赖容器,见博客《解决容器对组件的“侵入式”管理方法之一——服务定位器》。