首页 > 代码库 > 控制反转容器& 依赖注入模式 ---读感。

控制反转容器& 依赖注入模式 ---读感。

几个web框架 : sprint Avalon PicoContainer
class MovieLister
MovieFinder finder = ServiceLocator.movieFinder();

//单件注册表 注册的时候 载入一个已经确定好属性的服务定位器
class ServiceLocator...
public static MovieFinder movieFinder(){
return soleInstance.movieFinder;
}
private static ServiceLocator soleInstance;
private MovieFinder movieFinder;

public static void load(ServiceLocator arg) {
soleInstance = arg;
}
public ServiceLocator(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}

//test code
class Tester
private void configure(){
//说明服务定位器是有构造函数可以在这个时候来决定实用的movieFinder的。
ServiceLocator.load(new ServiceLocator(new ColonMovieFinder("Movie1.txt")));
}

public void testSimple(){
configure();
MovieLister lister = new MovieLister();
Movie[] movies = lister.moviesDirectedBy("Sergio");
assertEquals("Once Upon a Time in the West", movies[0].getTitle());
}
//ServiceLocator 应该是一个静态的全局变量,如此lister 才能直接载入。
//更复杂的情况: 服务定位器派生子类,并且将子类传递给注册表类变量。???
// 暴露一个静态方法,而不是直接访问该类实例的变量。

//-------单件模式 -------------//以上设计的设计模式


//为定位器使用分离接口:
//由于list 可能只需要使用一个服务,可以使用角色接口(role interface)这样不用使用全部的服务接口,只需要声明需要使用的接口就行了。
public interface MovieFinderLocator{
public MovieFinder movieFinder();
}

class MovieLister
MovieFinderLocator locator = ServiceLocator.locator();
MoiveFinder finder = locator.movieFinder();

class ServiceLocator
public static ServiceLocator locator(){
return soleInstance;
}
public MovieFinder movieFinder() {
return movieFinder;
}
private static ServiceLocator soleInstance;
private MovieFinder movieFinder;
//这个时候,由于使用了接口,就无法使用静态变量了,需要使用locator() 来 获取一个实例

//动态服务定位器 上面两个例子是静态的,但是我们也可以使用动态服务定位器,允许在其中注册需要的服务,并且在运行时动态按需获取。
// 如下 服务定位器是使用map来保存服务信息,而非放到字段中。
class ServiceLocator
private static ServiceLocator soleInstance;
public static void load(ServiceLocator arg){
soleInstance = arg;
}

private Map services = new HashMap();
public static Object getService(String key){
return soleInstance.services.get(key);
}
public void loadService(String key, Object service){
service.put(key, service);

}

class Tester
private void configure(){
ServiceLocator locator = new ServiceLocator();
locator.loadService("MovieFinder", new ColonMovieFinder("movie1.txt"));
ServiceLocator.load(locator);
}
class MovieLister
MovieFinder finder = (MovieFinder) ServiceLocator.getService("MovieFinder");

//Locator 和 Injection 同时使用的案列:
public class MyMovieLister implements MovieLister, Serviceable {
private MovieFinder finder;

public void service(ServiceManager manager) throws ServiceException {
finder = (MovieFinder) manager.lookup("finder");
}
}
//容器将中ServiceManager对象注入到list 中,ServiceManager 是一个服务定位器的,使用它来查找finder实例

//-------服务定位器和依赖注入的对比
服务定位器比较直观,但是所有的请求者都会需要依赖服务定位器
如果需要提供一个组件出去,最好还是使用注入的方式,因为无法控制使用者会使用什么样的实现,可以直接使用注入来定义对应的实现。

//-------构造注入和属性注入比较
两者都比较容易配置,而接口注入的方式十分容易在各处代码中泛滥。
构造注入和属性注入就涉及了是否应该在构造的时候就对属性进行赋值。
构造注入可以将属性设置为不可变的,并且可以明确意图。
属性注入在参数太多的时候很有必要,同时有多个方法来构造一个有效对象时,就可以使用Factory Method的模式。
同时如果对象有很多的构造器,并且对象间存在继承关系,这可能会导致构造器膨胀,由于子类的构造器需要调用父类的构造器然后再处理自己的参数。
//----代码配置还是文件配置
对于多数多处部署的应用程序来说,使用配置文件的方式比较好,我想是因为方便查看的原因。配置文件也多为XML,不过我们之前的项目多用json文件进行配置。
如果配置文件变得复杂了 就需要考虑换一个适合的编程语言来实现。
其中提到的:如果一个配置的逻辑变得复杂了,应该使用适合的语言来描述配置信息 这里没有考虑到对应的情况,不过觉得之前的表数据的配置,是否也可以用语言来实习?而不是一直增加怕配置文件。是否是会更加明了。
有很多组件有各自的配置文件,需要维护不同的配置文件,这种情况可以通过统一的编程接口来提供,可以分开配置文件。通过这个接口,可以管理配置文件???? 只想到了可以统一配置文件来实现,但是这里所说的统一配置文件接口的情境没有想好。

//------将配置和应用分离
服务的配置和应用分离,之前的应用就是这样的,单独配置应用的配置文件的地方。
一个设计原则:分离接口和具体的实现。
比如数据源的使用,测试的时候 可能是直接读取文件配置来着,但是在生产环境的时候,是读取服务器上的数据源JNDI的配置。

重点是应该将 服务配置从应用程序内部分离出来。

 

参考:

http://www.cnblogs.com/me-sa/archive/2008/07/30/IocDI.html

http://www.martinfowler.com/articles/injection.html

 

控制反转容器& 依赖注入模式 ---读感。