Java 依赖注入,延迟注入实践
一个简单(冗长)的问题,而不是简单的答案。通过使用一些DI框架(Spring、Guice),我得出了一个结论,即其他人提出的一些实践并不是那么容易实现。我似乎真的被困在这个层次上了 我将尽可能简单地介绍这一点,尽管一些细节可能会丢失。我希望问题会清楚 假设我有一个StringValidator,一个负责验证字符串的简单类Java 依赖注入,延迟注入实践,java,spring,dependency-injection,Java,Spring,Dependency Injection,一个简单(冗长)的问题,而不是简单的答案。通过使用一些DI框架(Spring、Guice),我得出了一个结论,即其他人提出的一些实践并不是那么容易实现。我似乎真的被困在这个层次上了 我将尽可能简单地介绍这一点,尽管一些细节可能会丢失。我希望问题会清楚 假设我有一个StringValidator,一个负责验证字符串的简单类 package test; import java.util.ArrayList; import java.util.List; public class StringVa
package test;
import java.util.ArrayList;
import java.util.List;
public class StringValidator {
private final List<String> stringList;
private final List<String> validationList;
private final List<String> validatedList = new ArrayList<String>();
public StringValidator(final List<String> stringList, final List<String> validationList) {
this.stringList = stringList;
this.validationList = validationList;
}
public void validate() {
for (String currentString : stringList) {
for (String currentValidation : validationList) {
if (currentString.equalsIgnoreCase(currentValidation)) {
validatedList.add(currentString);
}
}
}
}
public List<String> getValidatedList() {
return validatedList;
}
}
封装测试;
导入java.util.ArrayList;
导入java.util.List;
公共类字符串验证器{
私人最终名单;
私人最终清单验证清单;
private final List validatedList=new ArrayList();
公共StringValidator(最终列表stringList,最终列表validationList){
this.stringList=stringList;
this.validationList=validationList;
}
public void validate(){
用于(字符串currentString:stringList){
用于(字符串currentValidation:validationList){
if(currentString.equalsIgnoreCase(currentValidation)){
validatedList.add(当前字符串);
}
}
}
}
公共列表getValidatedList(){
返回validatedList;
}
}
依赖性尽可能低,允许进行以下简单测试:
package test;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class StringValidatorTest {
@Test
public void testValidate() throws Exception {
//Before
List<String> stringList = new ArrayList<String>();
stringList.add("FILE1.txt");
stringList.add("FILE2.txt");
final List<String> validationList = new ArrayList<String>();
validationList.add("FILE1.txt");
validationList.add("FILE20.txt");
final StringValidator stringValidator = new StringValidator(stringList, validationList);
//When
stringValidator.validate();
//Then
Assert.assertEquals(1, stringValidator.getValidatedList().size());
Assert.assertEquals("FILE1.txt", stringValidator.getValidatedList().get(0));
}
}
封装测试;
导入org.junit.Assert;
导入org.junit.Test;
导入java.util.ArrayList;
导入java.util.List;
公共类StringValidator测试{
@试验
public void testValidate()引发异常{
//以前
List stringList=新建ArrayList();
添加(“FILE1.txt”);
添加(“FILE2.txt”);
最终列表验证列表=新的ArrayList();
add(“FILE1.txt”);
添加(“FILE20.txt”);
最终StringValidator StringValidator=新的StringValidator(stringList,validationList);
//什么时候
stringValidator.validate();
//然后
Assert.assertEquals(1,stringValidator.getValidatedList().size());
Assert.assertEquals(“FILE1.txt”,stringValidator.getValidatedList().get(0));
}
}
如果我们想增加更多的灵活性,我们可以使用集合而不是列表,但我们假设这是不必要的
创建列表的类如下(使用任何其他接口标准):
封装测试;
导入java.util.List;
可串接的公共接口{
List getStringList();
}
包装试验;
导入java.util.ArrayList;
导入java.util.List;
公共类StringService实现了Stringable{
private List stringList=new ArrayList();
公共服务(){
createList();
}
//简化
私有void createList(){
添加(“FILE1.txt”);
stringList.add(“FILE1.dat”);
stringList.add(“FILE1.pdf”);
stringList.add(“FILE1.rdf”);
}
@凌驾
公共列表getStringList(){
返回字符串列表;
}
}
以及:
封装测试;
导入java.util.List;
可验证的公共接口{
List getValidationList();
}
包装试验;
导入java.util.ArrayList;
导入java.util.List;
公共类ValidationService实现可验证的{
private final List validationList=new ArrayList();
公共验证服务(){
createList();
}
//简化的。。。
私有void createList(){
add(“FILE1.txt”);
add(“FILE2.txt”);
add(“FILE3.txt”);
add(“FILE4.txt”);
}
@凌驾
公共列表getValidationList(){
返回验证列表;
}
}
我们有一个主类和一个主方法:
package test;
import java.util.List;
public class Main {
public static void main(String[] args) {
Validateable validateable = new ValidationService();
final List<String> validationList = validateable.getValidationList();
Stringable stringable = new StringService();
final List<String> stringList = stringable.getStringList();
//DI
StringValidator stringValidator = new StringValidator(stringList, validationList);
stringValidator.validate();
//Result list
final List<String> validatedList = stringValidator.getValidatedList();
}
}
封装测试;
导入java.util.List;
公共班机{
公共静态void main(字符串[]args){
Validateable Validateable=新的ValidationService();
最终列表validationList=validatable.getValidationList();
Stringable Stringable=新的StringService();
最终列表stringList=stringable.getStringList();
//DI
StringValidator StringValidator=新的StringValidator(stringList,validationList);
stringValidator.validate();
//结果表
最终列表validatedList=stringValidator.getValidatedList();
}
}
假设这些类在运行时(当用户需要时)生成列表。
“直接”(静态)绑定是不可能的
如果我们希望提供尽可能低的耦合,我们将使用列表为我们提供运行验证(StringValidator)所需的数据
但是,如果我们想使用容器来帮助我们处理“粘合代码”,我们可以将这两个“服务”注入到StringValidator中。这将为我们提供正确的数据,但代价是耦合。另外,StringValidator将承担实际调用依赖项的额外责任
如果我以这种方式使用委托,我的代码就会被不需要的职责(不是我想要的东西)弄得乱七八糟
如果我不这样做,我就看不出有什么办法可以做到这一点(提供商可以向我提供正确的列表,但依赖性仍然存在)
更一般的问题是-是否有一种方法可以使用DI框架实际创建完全解耦的应用程序,或者这是一种理想的方法?
在哪种情况下你会使用DI框架,而在哪种情况下你不会?
DI框架真的是“新”吗?
谢谢。我有点困惑,但您的意思是希望在不依赖任何类的情况下使用DI吗?使用注释或自定义类加载器可能实现这一点,但这将非常缓慢,而且非常困难。也许你可以澄清一下你想要什么?我有点困惑,但你的意思是你想要在不依赖任何类的情况下使用DI吗?这可以通过注释或自定义
package test;
import java.util.List;
public interface Validateable {
List<String> getValidationList();
}
package test;
import java.util.ArrayList;
import java.util.List;
public class ValidationService implements Validateable {
private final List<String> validationList = new ArrayList<String>();
public ValidationService() {
createList();
}
//Simplified...
private void createList() {
validationList.add("FILE1.txt");
validationList.add("FILE2.txt");
validationList.add("FILE3.txt");
validationList.add("FILE4.txt");
}
@Override
public List<String> getValidationList() {
return validationList;
}
}
package test;
import java.util.List;
public class Main {
public static void main(String[] args) {
Validateable validateable = new ValidationService();
final List<String> validationList = validateable.getValidationList();
Stringable stringable = new StringService();
final List<String> stringList = stringable.getStringList();
//DI
StringValidator stringValidator = new StringValidator(stringList, validationList);
stringValidator.validate();
//Result list
final List<String> validatedList = stringValidator.getValidatedList();
}
}
public class Main {
@Autowired
private Validateable validateable;
@Autowired
private Stringable stringable;
public void main() {
final List<String> validationList = validateable.getValidationList();
final List<String> stringList = stringable.getStringList();
StringValidator stringValidator = new StringValidator(stringList, validationList);
stringValidator.validate();
final List<String> validatedList = stringValidator.getValidatedList();
}
public static void main(String[] args) {
Container container = new ...;
container.get(Main.class).main();
}
}
public class StringValidator {
private SourceOfStrings stringSource;
private SourceOfStrings validationStringSource;
private final List<String> validatedList = new ArrayList<String>();
...
public void validate() {
for (String currentString : stringSource.getStrings()) {
for (String currentValidation : validationStringSource.getStrings()) {
if (currentString.equalsIgnoreCase(currentValidation)) {
validatedList.add(currentString);
}
}
}
}
public List<String> getValidatedList() {
return validatedList;
}
}
interface SourceOfStrings {
List<String> getStrings();
}
package test;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
@Component
public class StringList extends ArrayList<String> {
}
package test;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
@Component
public class ValidationList extends ArrayList<String> {
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:component-scan base-package="test"/>
<!--<bean id="validationList" class="java.util.ArrayList" scope="singleton"/>-->
<!--<bean id="stringList" class="java.util.ArrayList" scope="singleton"/>-->
</beans>
package test;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
@Component
public class StringService implements Stringable {
private List<String> stringList;
@Inject
public StringService(final ArrayList<String> stringList) {
this.stringList = stringList;
createList();
}
//Simplified
private void createList() {
stringList.add("FILE1.txt");
stringList.add("FILE1.dat");
stringList.add("FILE1.pdf");
stringList.add("FILE1.rdf");
}
@Override
public List<String> getStringList() {
return stringList;
}
}
package test;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
@Component
public class ValidationService implements Validateable {
private List<String> validationList;
@Inject
public ValidationService(final ArrayList<String> validationList) {
this.validationList = validationList;
createList();
}
//Simplified...
private void createList() {
validationList.add("FILE1.txt");
validationList.add("FILE2.txt");
validationList.add("FILE3.txt");
validationList.add("FILE4.txt");
}
@Override
public List<String> getValidationList() {
return validationList;
}
}
package test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class StringValidator {
private List<String> stringList;
private List<String> validationList;
private final List<String> validatedList = new ArrayList<String>();
@Autowired
public StringValidator(final ArrayList<String> stringList,
final ArrayList<String> validationList) {
this.stringList = stringList;
this.validationList = validationList;
}
public void validate() {
for (String currentString : stringList) {
for (String currentValidation : validationList) {
if (currentString.equalsIgnoreCase(currentValidation)) {
validatedList.add(currentString);
}
}
}
}
public List<String> getValidatedList() {
return validatedList;
}
}
package test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class Main {
@Autowired
private StringValidator stringValidator;
public void main() {
stringValidator.validate();
final List<String> validatedList = stringValidator.getValidatedList();
for (String currentValid : validatedList) {
System.out.println(currentValid);
}
}
public static void main(String[] args) {
ApplicationContext container = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml");
container.getBean(Main.class).main();
}
}