gpt4 book ai didi

java - 依赖注入(inject),延迟注入(inject)实践

转载 作者:行者123 更新时间:2023-11-30 07:26:19 36 4
gpt4 key购买 nike

一个简单(且冗长)的问题,而不是一个简单的答案。使用一些 DI 框架(Spring,Guice)我得出一个结论,即其他人提出的一些实践并不那么容易实现。我似乎真的停留在这个层面上。

尽管可能会遗漏一些细节,但我会尽可能简单地介绍它。我希望问题很清楚。

假设我有一个 StringValidator,这是一个负责验证字符串的简单类。

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;
}
}

依赖性尽可能低,允许像这样的简单测试:

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));
}
}

如果我们想进一步增加灵 active ,我们可以使用 Collection<> 而不是 List<>,但我们假设这不是必需的。

创建列表的类如下(使用任何其他接口(interface)标准):

package test;

import java.util.List;

public interface Stringable {
List<String> getStringList();
}

package test;

import java.util.ArrayList;
import java.util.List;

public class StringService implements Stringable {

private List<String> stringList = new ArrayList<String>();

public StringService() {
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 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;
}
}

我们有一个带有 main 方法的主类:

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();
}
}

假设这些类在运行时(当用户想要时)生成列表。“直接”(静态)绑定(bind)是不可能的。

如果我们想提供尽可能低的耦合,我们将使用列表来为我们提供运行验证所需的数据 (StringValidator)。

但是,如果我们想使用容器来帮助我们处理“胶水代码”,我们可以将这两个“服务”注入(inject)到 StringValidator 中。这将为我们提供正确的数据,但要以 COUPLING 为代价。此外,StringValidator 将承担实际调用依赖项的额外责任。

如果我以这种方式使用委托(delegate),我的代码就会因不需要的责任(不是我想要的)而变得困惑。

如果我不这样做,我看不出有什么可行的方法(提供者可以为我提供正确的列表,但是,依赖关系仍然存在)。

更一般的问题是 - 有没有一种方法可以使用 DI 框架实际创建一个完全解耦的应用程序,或者这是某种理想的方法?在什么情况下你使用 DI 框架,在什么情况下不使用?DI 框架真的是“新的新”吗?

谢谢。

最佳答案

这是一个有点难回答的问题,特别是因为它是一个人为的例子,但如果我们假设你的类已经完全按照你想要的方式设计,那么依赖注入(inject)的正确应用就很简单了。您似乎专注于 StringValidator 的可测试性,并试图通过依赖注入(inject)对它做一些神奇的事情。您应该关注可测试性的地方在您的 Main 类中。这就是您引入紧耦合和不可测试代码的地方,也是 DI 容器将显示其值(value)的地方。正确应用 DI 和 IoC 原则可能会导致这样的结果:

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();
}
}

换句话说,您所有的手动接线都将交由 DI 容器控制。这就是重点。就个人而言,我不会对此感到满意,因为您仍然有一些看起来像“组件”类的东西——StringValidator——由您的代码实例化。我会研究重新设计事物的方法,以摆脱代码中的这种硬依赖,并将该创建也移交给容器。

至于这个“新新”,不,DI 容器不是新的。他们已经存在了很长一段时间。如果您的意思是“我应该使用一个吗?”,那么我想我的回答通常是"is",尽管模式比任何特定的实现都更重要。好处是公认的和接受的,它更像是一种思维方式,而不是实际的框架。正如我刚刚演示的那样,您的 Main 类本质上是一个原始的 DI 容器。

更新:如果您最关心的是如何处理 StringValidator 的输入,则有几个选项。您的“stringList”和“validationList”没有理由不能由 DI 容器管理并注入(inject)到您的 StringValidator 中。然后这些列表的来源取决于容器。它们可能来自您的其他对象或通过测试注入(inject)。或者,也许您希望更改围绕 StringValidator 如何获取其输入的抽象?在那种情况下,也许像这样的东西会更适合您的需求:

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();
}

注意:不是线程安全的。在线程环境中,我肯定会采取额外的步骤来消除将结果存储在字段中并调用额外的方法来获取它的需要。

关于java - 依赖注入(inject),延迟注入(inject)实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10384473/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com