Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 当一个类有许多依赖项,但基于某些条件只需要使用其中的一些依赖项时的设计方法_Java_Spring_Java 8 - Fatal编程技术网

Java 当一个类有许多依赖项,但基于某些条件只需要使用其中的一些依赖项时的设计方法

Java 当一个类有许多依赖项,但基于某些条件只需要使用其中的一些依赖项时的设计方法,java,spring,java-8,Java,Spring,Java 8,我有多个实现接口并返回对象的类 public interface DataFetcher { Data getData(Info info); } public class Data { private String name; private String value; } @Component public class DataPointA implements DataFetcher { @Override public Data getDat

我有多个实现接口并返回对象的类

public interface DataFetcher {
    Data getData(Info info);
}

public class Data {
    private String name;
    private String value;
}


@Component
public class DataPointA implements DataFetcher {
    @Override
    public Data getData(Info info) {
        //..Do some processing
        return new Data("SomeName", valueComputed);
    }
}
现在我有大约20个数据点,它们实现了DataFetcher类并返回数据对象

我将所有数据点自动关联到一个类,并根据某些条件使用某些数据点

@Component
public class DataComputer {
    @Autowired
    private DataPointA dataPointA;

    @Autowired
    private DataPointB dataPointB;
    .
    .
    .

    public void computeData(String inputType, Info info) {
        List<DataFetcher> dataFecthers;
        switch(inputType) {
            case "typeA" : dataFecthers  = ImmutableList.of(dataPointA, dataPointB);
                            break;

            .
            .
            .
            case "typeD" : dataFecthers  = ImmutableList.of(dataPointE, dataPointF, dataPointG);
                            break;
        }

        dataFetcher.forEach(dataPoint -> {
            //Do some processing with  dataPoint.getData(info)
        })
    }
}
@组件
公共类数据计算机{
@自动连线
私有数据点a数据点a;
@自动连线
私有数据点b数据点b;
.
.
.
公共无效计算数据(字符串输入类型,信息){
列出数据表;
开关(输入类型){
案例“typeA”:dataFecthers=ImmutableList.of(dataPointA,dataPointB);
打破
.
.
.
案例“类型化”:dataFecthers=ImmutableList.of(dataPointE、dataPointF、dataPointG);
打破
}
dataFetcher.forEach(数据点->{
//使用dataPoint.getData(info)执行一些处理
})
}
}
可以看出,DataComputer类将有一个完整的依赖项列表,这些依赖项可能变得不可管理。此外,基于inputType使用的数据点在手之前已知,因此可以提取出来。这是我的尝试:

@Component 
public class DataComputationPointDecider {
    @Autowired
    private DataPointA dataPointA;

    @Autowired
    private DataPointB dataPointB;

    .
    .
    .

    @Bean
    public Map<String, List<DataFetcher>> getDataComputationPoints() {
        return new ImmutableMap.Builder<String, List<DataFetcher>>()
            .put("typeA", ImmutableList.of(dataPointA, dataPointB))
            .put("typeD", ImmutableList.of(dataPointE, dataPointF, dataPointG))
            .build();
    }
}
@组件
公共类数据计算点决策器{
@自动连线
私有数据点a数据点a;
@自动连线
私有数据点b数据点b;
.
.
.
@豆子
公共地图getDataComputationPoints(){
返回新的ImmutableMap.Builder()
.put(“typeA”,不可变列表(dataPointA,dataPointB))
.put(“类型化的”,不可变的list.of(dataPointE,dataPointF,dataPointG))
.build();
}
}
然后,我的数据计算机依赖性降低:

@Component
public class DataComputer {
    @Autowired
    private Map<String, List<DataFetcher>> dataComputationPoints;

    public void computeData(String inputType, Info info) {
        List<DataFetcher> dataFecthers = dataComputationPoints.get(inputType);
        dataFetcher.forEach(dataPoint -> {
            //Do some processing with  dataPoint.getData(info)
        })
    }
}
@组件
公共类数据计算机{
@自动连线
私有地图数据点;
公共无效计算数据(字符串输入类型,信息){
List dataFecthers=dataComputationPoints.get(inputType);
dataFetcher.forEach(数据点->{
//使用dataPoint.getData(info)执行一些处理
})
}
}

有更好的设计方法吗?

您考虑过使用Factory模式吗?这允许您根据特定条件提交对象实例请求。

我看不出您的方法有任何重大错误。但我建议还有一个选择

您可以让
DataFetcher
决定或说出它可以处理的输入类型,而不是维护将
inputType
映射到
DataFetcher
列表的映射

但这需要将
DataFetcher的接口更改为

public interface DataFetcher {
    boolean canHandle(String inputType);
    Data getData(Info info);
}
这些实现看起来像

@Component
public class DataPointA implements DataFetcher {
    @Override
    boolean canHandle(String inputType) {
         return "typeA".equals(inputType);
    }

    @Override
    public Data getData(Info info) {
        //..Do some processing
        return new Data("SomeName", valueComputed);
    }
}
然后,您可以将所有
数据获取程序
作为一个列表注入(不需要为每个列表添加一个
@Autowired
字段),并将其作为

@Autowired
List<DataFetcher> dataFetchers;

...

dataFetchers.stream()
     .filter(dataFetcher -> dataFetcher.canHandle(inputType))
     .forEach(dataFetcher.getData(info));
@Autowired
列出数据获取程序;
...
dataFetchers.stream()
.filter(dataFetcher->dataFetcher.canHandle(inputType))
.forEach(dataFetcher.getData(info));
优势:

在当前方法中,如果添加新的
DataFetcher
实现,则需要添加
@AutoWired
字段/成员并修改(getDataComputationPoints)映射。但是,有了它,
DataFetcher
可以处理的输入类型是由它自己指定的,因此您只需要为新的输入类型添加新的类

参考

更新:

缺点

  • 输入类型是在类中指定的,这意味着您无法轻松找到给定输入类型的
    数据获取程序列表
    (数据点)

  • 如果您需要删除对inputType的支持,那么您需要再次访问每个实现(从
    canHandle
    中删除该inputType)。在您的方法中,只需删除一个映射条目


  • 嗯,说得好。在工厂模式的情况下,工厂将负责返回给定输入类型的
    列表
    ,而不是直接对其进行自动接线。如果我能正确理解你的意图,这将是我思想的延伸。我喜欢你指出的优点。我一直在考虑传递输入类型的另一种方法。我没有在代码中说明特定数据点需要使用哪些数据点,而是在考虑是否可以将其扩展到配置文件中包含这些数据的方式,如果需要交换数据点,则需要更少的java代码更改。对于文件{“typeA”:[“DataPointA”,“DataPointB”],“typeB”:[“DataPointC”,“DataPointE”]}中的ex,它有其优点和缺点。在配置中维护java类名(如
    DataPointA
    )是很脆弱的。如果后来有人决定给它重命名怎么办?即使在这种情况下,您也需要将字符串
    DataPointA
    映射到
    DataPointA
    对象,这不是简单的(使用反射?任何其他方式?)True。不需要将配置文件名映射为类名。那就简单多了。一种方法是使用一个枚举,该枚举具有与配置文件中的名称列表匹配的字符串,以及一个映射器,该映射器为每个枚举值返回正确的实现。这样,更改类名是安全的。然后您无论如何都需要更改该枚举(这是java代码):)然后每次添加新的实现时,您都需要1)更改配置2)向枚举添加条目,很容易忘记其中一项或两项。此外,您还需要处理configFair中的拼写错误。我编辑了我的答案,添加了这种方法的缺点。但是要删除类型的实现,只需转到该实现并更改
    canHandle
    。很难完全删除一个类型