如何在不违反依赖注入原则的前提下创建含其他类实例列表的类?
如何在遵循依赖注入原则的前提下实现Foo实例管理类
嘿,针对你的问题,咱们可以通过依赖倒置+构造函数注入的方式来实现,完全符合依赖注入原则,同时还能让代码更灵活、易测试。下面一步步来拆解:
核心思路:解耦职责
依赖注入的核心是依赖抽象而非具体实现,并且把对象的创建控制权交给外部。咱们要把「从CSV读取数据创建Foo」和「管理Foo列表做计算」这两个职责分开:
- 管理类只负责业务计算,不关心数据从哪来
- 专门的组件负责数据读取和Foo实例化,管理类依赖这个组件的抽象接口
第一步:抽象数据提供的接口
先定义一个抽象接口,用来规范「提供Foo实例列表」的行为,这样管理类只需要依赖这个接口,不用管具体是从CSV还是别的地方来的数据:
import java.util.List; public interface FooDataProvider { List<Foo> provideFoos(); }
第二步:实现CSV版的数据提供者
把原来要放在管理类里的CSV读取、解析逻辑,单独抽成一个实现类,专门负责从CSV文件生成Foo列表:
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class CsvFooDataProvider implements FooDataProvider { private final String csvFilePath; // 这里可以根据需要注入其他依赖,比如CSV解析库的实例,保持灵活性 public CsvFooDataProvider(String csvFilePath) { this.csvFilePath = csvFilePath; } @Override public List<Foo> provideFoos() { List<Foo> fooList = new ArrayList<>(); try (BufferedReader br = new BufferedReader(new FileReader(csvFilePath))) { String line; // 跳过表头(如果你的CSV有表头的话,没有可以删掉这行) br.readLine(); while ((line = br.readLine()) != null) { String[] args = line.split(","); fooList.add(new Foo(args)); } } catch (IOException e) { // 这里可以根据业务需求处理异常,比如封装成自定义异常抛出 throw new RuntimeException("Failed to load Foo data from CSV", e); } return fooList; } }
第三步:实现依赖注入的管理类
管理类通过构造函数注入FooDataProvider接口,在初始化时获取Foo列表,之后专注于业务计算:
import java.util.List; public class FooManager { private final List<Foo> fooList; // 构造函数注入依赖,这是最推荐的DI方式(强制依赖,不可为空) public FooManager(FooDataProvider dataProvider) { this.fooList = dataProvider.provideFoos(); } // 示例计算方法,你可以替换成自己的业务逻辑 public int calculateSumOfFirstCoef() { return fooList.stream().mapToInt(Foo::getFirstCoef).sum(); } // 其他业务方法... }
第四步:组装依赖并使用
在应用的入口(比如main方法)或者配置类里,创建具体的数据提供者实例,注入给管理类:
public class Main { public static void main(String[] args) { // 创建具体的CSV数据提供者 FooDataProvider csvProvider = new CsvFooDataProvider("your/file/path/data.csv"); // 注入依赖创建管理类实例 FooManager fooManager = new FooManager(csvProvider); // 调用管理类的业务方法 int total = fooManager.calculateSumOfFirstCoef(); System.out.println("Total of first coefficients: " + total); } }
为什么这符合依赖注入原则?
- 依赖倒置:FooManager依赖的是抽象的
FooDataProvider,而不是具体的CsvFooDataProvider。以后如果要从数据库、API或者内存读取Foo数据,只需要新增一个FooDataProvider的实现类,完全不用修改FooManager的代码。 - 控制反转:创建Foo列表的控制权从FooManager转移到了外部的提供者类,FooManager只需要专注于业务计算,不用关心数据来源和解析细节。
- 可测试性:单元测试时,你可以写一个
MockFooDataProvider,返回预设的Foo列表,不用依赖真实的CSV文件,测试起来更简单。
内容的提问来源于stack exchange,提问作者Elena Heinsalu
相关产品推荐
相关产品推荐

