一个简单(冗长)的问题,而不是简单的答案。通过使用某些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)); }}如果我们想进一步提高灵活性,可以使用Collection 而不是List ,但让我们假设这不是必需的。创建列表的类如下(使用任何其他接口标准):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方法的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(); }}因此,假设类在运行时(当用户需要时)生成列表。“直接”(静态)绑定是不可能的。如果我们想提供尽可能低的耦合,我们将使用列表为我们提供运行validation(StringValidator)所需的数据。但是,如果我们想使用容器来帮助我们处理“胶水代码”,则可以将两个“服务”注入StringValidator。这样可以为我们提供正确的数据,但是要付出耦合的代价。而且,StringValidator将额外承担实际调用依赖项的责任。如果我以这种方式使用委派,则会使我的代码杂乱无章(这不是我想要的)。如果我不这样做,我看不到有什么办法可以做到这一点(Provider可以为我提供正确的列表,但是依赖项仍然存在)。更为笼统的问题是-是否有一种方法可以使用DI框架实际创建完全解耦的应用程序,或者这是理想的选择吗?在这种情况下,您是否使用DI框架?DI框架真的是“新”吗?谢谢。 (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 这是一个很难回答的问题,尤其是因为这是一个人为的示例,但是如果我们假设您的类已经按照您的要求进行了完全正确的设计,那么正确使用依赖项注入就很简单。您似乎专注于StringValidator的可测试性,并尝试通过依赖项注入对其做一些魔术。您应该担心可测试性的地方是您的主班。那就是您引入紧密耦合和不可测试的代码的地方,而DI容器将显示其价值。正确应用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容器不是新的。他们已经存在了一段时间。如果您的意思是“我应该使用一个吗?”,那么我猜我的答案通常是“是”,尽管该模式比任何特定实现都重要。好处是公认的,可以接受的,它比实际框架更是一种思考方式。正如我刚刚演示的那样,您的Main类本质上是一个原始的DI容器。更新:如果您最关心的是如何处理StringValidator的输入,则有两种选择。没有理由不能由DI容器管理“ stringList”和“ validationList”并将其注入到StringValidator中。然后,这些列表的来源取决于容器。它们可能来自您的其他对象,也可能是经过测试注入的。或者,也许您正在寻找更改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();}注意:不是线程安全的。在线程环境中,我肯定会采取额外的步骤来消除将结果存储在字段中并调用额外的方法调用以获取结果的需要。 (adsbygoogle = window.adsbygoogle || []).push({});
10-06 12:38