依赖注入的6种方式
一、Setter注入-Spring Setter注入是指外部程序通过调用setter方法为客户端注入所依赖的对象。Spring就有采用这种方式。 publicclassClient{ privateService1service1; publicvoidsetService1(Service1service1){ this.service1=service1; } publicvoiddoSomething(){ service1.execute(); } publicstaticvoidmain(String[]args){ ApplicationContextctx=newClassPathXmlApplicationContext("pattern/part2/chapter6/setter/spring-beans.xml"); Clientclient=(Client)ctx.getBean("client"); client.doSomething(); } } 配置文件 <beanid="client"class="com.persia.client"> <propertyname="service1"ref="service1"/> </bean> mock publicclassClientTestDrive{ publicvoidtestDoSomething(){ Clientclient=newClient(); MockService1mockService1=newMockService1(); client.setService1(mockService1); client.doSomething(); assertEquals(mockService1.isExecuted(),true,"Testfailed"); } publicstaticvoidmain(String[]args){ newClientTestDrive().testDoSomething(); } privatestaticvoidassertEquals(booleanactual,booleanexpected,Stringmessage){ if(actual!=expected)thrownewIllegalArgumentException(message); } privatestaticclassMockService1implementsService1{ privatebooleanexecuted; publicbooleanisExecuted(){ returnexecuted; } @Override publicvoidexecute(){ executed=true; } } } 二、Constructor注入-PicoContainerConstructor注入就是通过带参数的构造器注入依赖对象。PicoContainer就是采用这种方式注入的。 publicclassClient{ privateService1service1; publicClient(Service1service1){ this.service1=service1; } publicvoiddoSomething(){ service1.execute(); } privatestaticMutablePicoContainerconfigure(){ MutablePicoContainerpico=newDefaultPicoContainer(); pico.addComponent(Service1Impl.class);//registeranimplementationofService1 pico.addComponent(Service2Impl.class); pico.addComponent(Client.class); returnpico; } publicstaticvoidmain(String[]args){ MutablePicoContainerpico=configure(); Clientclient=pico.getComponent(Client.class); client.doSomething(); } } mock publicclassClientTestDrive{ publicvoidtestDoSomething(){ MockService1mockService1=newMockService1(); Clientclient=newClient(mockService1); client.doSomething(); assertEquals(mockService1.isExecuted(),Stringmessage){ if(actual!=expected)thrownewIllegalArgumentException(message); } privatestaticclassMockService1implementsService1{ privatebooleanexecuted; publicbooleanisExecuted(){ returnexecuted; } @Override publicvoidexecute(){ executed=true; } } } 三、Annotation注入-Guice只要接口是@Retention(RUNTIME)的,就可以在运行时期通过反射读取。Annotation注入的方式就是把实例化信息和对象之间的依赖关系信息使用注解的形式表达,只要在运行时期得到它们,就知道如何初始化服务对象了。Guice就是采用这种方式的。注解可以注解在方法、构造器、属性上面。
@ImplementedBy(Service1Impl.class) publicinterfaceService1{ voidexecute(); } publicclassClient{ privateService1service1; @Inject publicClient(Service1service1){ this.service1=service1; } publicvoiddoSomething(){ service1.execute(); } publicstaticvoidmain(String[]args){ Injectorinjector=Guice.createInjector(); Clientclient=injector.getInstance(Client.class); client.doSomething(); } } mock publicclassClientTestDrive{ publicvoidtestDoSomething(){ MockService1mockService1=newMockService1(); Clientclient=newClient(mockService1); client.doSomething(); assertEquals(mockService1.isExecuted(),Stringmessage){ if(actual!=expected)thrownewIllegalArgumentException(message); } privatestaticclassMockService1implementsService1{ privatebooleanexecuted; publicbooleanisExecuted(){ returnexecuted; } @Override publicvoidexecute(){ executed=true; } } } 四、Interface注入-Avalon 客户端通过实现容器/框架所规范的某些特殊接口,在返回这些依赖对象之前,容器回调这些接口方法,注入依赖的服务对象。Apache的Avalon就是采用这种方式注入的。 publicinterfaceServiceAware{ voidinjectService(Serviceservice); } publicclassClientimplementsServiceAware{ privateServiceservice; @Override publicvoidinjectService(Serviceservice){ this.service=service; } publicvoiddoSomething(){ service.execute(); } publicstaticvoidmain(String[]args){ InterfaceInjector.configure(); Clientclient=InterfaceInjector.getInstance(Client.class); client.doSomething(); } } 接口注入 publicclassInterfaceInjector{ privatestaticInterfaceInjectorinjector; privateMap<Class,Object>services=newHashMap<Class,Object>(); publicstaticvoidconfigure(){ load(newInterfaceInjector()); } publicstatic<T>TgetInstance(Class<T>clazz){ returninjector.loadService(clazz); } privatestaticvoidload(InterfaceInjectorcontainer){ InterfaceInjector.injector=container; } @SuppressWarnings("unchecked") private<T>TloadService(Class<T>clazz){ Objectservice=injector.services.get(clazz); if(service!=null){ return(T)service; } try{ service=clazz.newInstance(); if(serviceinstanceofServiceAware){ ((ServiceAware)service).injectService(newServiceImpl()); } injector.services.put(clazz,service); }catch(InstantiationExceptione){ e.printStackTrace(); }catch(IllegalAccessExceptione){ e.printStackTrace(); } return(T)service; } } mock publicclassClientTestDrive{ publicvoidtestDoSomething(){ MockServicemockService=newMockService(); Clientclient=newClient(); client.injectService(mockService); client.doSomething(); assertEquals(mockService.isExecuted(),Stringmessage){ if(actual!=expected)thrownewIllegalArgumentException(message); } privatestaticclassMockServiceimplementsService{ privatebooleanexecuted; publicbooleanisExecuted(){ returnexecuted; } @Override publicvoidexecute(){ executed=true; } } } 五、Parameter注入外部程序通过函数参数,给客户端注入所依赖的服务对象。构造器注入和setter注入都可以看成是参数注入的变形。 publicclassClient{ publicvoiddoSomething(Serviceservice){ service.execute(); } publicstaticvoidmain(String[]args){ //createaservice Serviceservice=newServiceImpl(); //putnew-createdserviceinstancebyinputparameter newClient().doSomething(service); } } mock publicclassClientTestDrive{ publicvoidtestDoSomething(){ MockServicemockService=newMockService(); Clientclient=newClient(); client.doSomething(mockService); assertEquals(mockService.isExecuted(),Stringmessage){ if(actual!=expected)thrownewIllegalArgumentException(message); } privatestaticclassMockServiceimplementsService{ privatebooleanexecuted; publicbooleanisExecuted(){ returnexecuted; } @Override publicvoidexecute(){ executed=true; } } } 六、其他形式的注入 诸如Guice使用的Providers的注入方式等。 小结:依赖注入的好处:把实例化的过程交给框架/容器来处理,这样可以更专注于业务逻辑的开发。Setter和Contructor注入是常见的注入方式。 摘自《漫谈设计模式》 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |