无法将类分解为较小的部分

5
我有一个把我的类分成小部分的问题。我们有一个糟糕的情况,一个Dto持有30个不同的Dtos。现在我们需要这个selectDto的映射,这也迫使我们制作30个不同的映射类。(我们在项目中还使用mapstruct,这种情况不同于mapstruct可以处理的情况)
现在我的问题开始了:
我把所有的映射都放在了相应的类中。在base selectDto中,我的构造函数中有26个mapper,这太可怕了:
SonarLint: 构造函数有26个参数,大于7个获授权的参数。
我想出了一种分割这种场景的方法,但是我找不到好的方法。有什么建议吗?
我的构造函数拥有26个参数:
    AssignedSelectMapper(AssignedOpDtoMapper assignedOpDtoMapper,
        AssignedOrderDtoMapper assignedOrderDtoMapper
// many more constructor parameters
) {
        this.assignedOptionCodeDtoMapper = assignedOptionCodeDtoMapper;
        this.assignedOrderCriteriaDtoMapper = assignedOrderCriteriaDtoMapper;
        // all settings
}

我的公共函数用于映射,每个映射都调用私有函数:

    public List<AssignedSelect> assignSelectFrom(SelectDto selectDto) {
        Objects.requireNonNull(selectionDto, "selectionDto can not be NULL");

        List<AssignedSelect> assignedSelects= new ArrayList<>();
        assignedSelects.addAll(this.mapOps(selectionDto.getOps()));
        assignedSelects.addAll(this.mapOra(selectionDto.getOra()));
        assignedSelects.addAll(this.mapOrs(selectionDto.getOrs()));
        assignedSelects.addAll(this.mapSs(selectionDto.getSs()));
        assignedSelects.addAll(this.mapDels(selectionDto.getDels()));
        assignedSelects.addAll(this.mapMs(selectionDto.getMs()));
        assignedSelects.addAll(this.mapBrs(selectionDto.getBrs()));
        assignedSelects.addAll(this.mapEqs(selectionDto.getEqs()));
        assignedSelects.addAll(this.mapPaints(selectionDto.getPaints()));
        assignedSelects.addAll(this.mapBas(selectionDto.getBas()));
// more ...
// and more...
return assignedSelects;
}

// 我的私有函数示例,它调用相应的映射器,其中所有的私有函数都由不同类型的类组成,例如这里的OptionCodeDto。它们不继承自同一接口/类,也不能这样做。

 private List<AssignedSelectionCriteria> mapOps(List<OptionCodeDto> optionCodeDtos) {
        return this.assignedOpDtoMapper.mapCriterias(opDtos);
    }

// 这里是反向映射。我需要一种不同于我的映射返回类型的类

// this is my public function for mapping.
public void assignSelectionTo(SelectionDto selectionDto,
    List<AssignedSelectionCriteria> assignedSelectionCriterias) {

    setOptionCodes(selectionDto, copyCriterias);
    setOrderCriteria(selectionDto, copyCriterias);
    // many more
}

这是反向映射私有函数,每个映射类都返回不同类型的DTO,例如OptionCodeDto,其中这些DTO都不继承自同一类。

private void setOptionCodes(SelectionDto selectionDto, List<AssignedSelectionCriteria> assignedSelectionCriterias) {
// this is where I have trouble, each mapping returns different Dto's
        List<OptionCodeDto> optionCodeDtos =
             this.assignedOptionCodeDtoMapper.mapAssignedCriterias(assignedSelectionCriterias;
        selectionDto.setOptionCodes(optionCodeDtos);
    }

也许这可以帮助:https://softwareengineering.stackexchange.com/questions/311297/constructor-with-tons-of-parameters-vs-builder-pattern - Akceptor
所有私有函数都会接收 List<OptionCodeDto> optionCodeDto 作为参数,还是类型可能不同? - davidxxx
是的,它们都不同,并且不能从同一界面/基类扩展。 - cmlonder
好的。您应该在问题中指定它,因为它对整体解决方案很重要。 - davidxxx
谢谢,我已经更新了。 - cmlonder
3个回答

2
创建一个名为AssignedSelectProvider的接口。
interface AssignedSelectProvider
{
    List<AssignedSelect> getAssignedSelects();
}

每个映射器都实现了接口,并且每个私有方法都移动到相关的类中:
class AssignedOpDtoMapper implements AssignedSelectProvider
{
    public List<AssignedSelect> getAssignedSelects()
    {
        return mapOps(getOps());
    }
}
< p > AssignedSelectMapper 在构造函数中获取供应商列表,而不是 26 个参数:

class AssignedSelectMapper
{
    AssignedSelectMapper(List<AssignedSelectProvider> mappers)
    {
        //...
    }
}

现在只需要一个参数,而不是26个参数。


2

这类似于对@Michaels answer的扩展。

使用接口的想法非常好。但是在我看来,接口可以更改为更适合您的用例:

interface SelectDtoProcessor {
     void process(SelectDto dto, 
                  Consumer<? super Collection<? extends AssignedSelect>> action);
}

现在每个映射器都实现了这个接口:
class AssignedOpDtoMapper implements SelectDtoProcessor {
    @Override
    public void process(SelectDto dto, 
                        Consumer<? super Collection<? extends AssignedSelect>> action){
        List<OptionCodeDto> ops = dto.getOps();
        consumer.accept(mapCriterias(ops));
}

然后将所有这些Processors注入到您的主类中:

private final List<SelectDtoProcessor> processors;

AssignedSelectMapper(List<SelectDtoProcessor> processors) {
    this.processors = processors;
}

最后,在您的方法中迭代所有处理器:
public List<AssignedSelect> assignSelectFrom(SelectDto selectDto) {
    Objects.requireNonNull(selectionDto, "selectionDto can not be NULL");

    List<AssignedSelect> assignedSelects= new ArrayList<>();
    for(SelectDtoProcessor processor: processors) {
        processor.process(selectDto, assignedSelects::addAll);
    }
    return assignedSelects;
}

1

这有两种解决方案:

1. 将所有内容作为一个参数传递:

假设您在一个构造函数中传递了30个参数(即DTOs),那么请创建一个主DTO,将所有30个DTO放入其中,并将该DTO作为一个参数进行传递。

例如:

public class MasterDTO{

private ChildDto1 childDto1 ;
private ChildDto2 childDto2 ;
private ChildDto3 childDto3 ;
...
..
private ChildDto30 childDto30 ;
//public getter setter methds
}

传递30个DTO的调用类

public class Caller{
  Functional fun = new Functional(masterDTO);

}

功能类,期望值为30 DTOS。
class Functional{
  private ChildDto1 childDto1 ;
  private ChildDto2 childDto2 ;
  private ChildDto3 childDto3 ;
...
...

public Functional(MasterDTO masterDTO){
childDto1 = masterDTO.getChildDto1();
childDto2 = masterDTO.getChildDto2();
childDto3 = masterDTO.getChildDto3();

...
...

childDto30 = masterDTO.getChildDto30();
}

}

2. 使用 Setter 方法:

只需将 7 个元素作为构造函数的参数传递,然后使用对象并调用 Setter 方法来设置其余的 23 个元素。

调用方类用于传递 30 个 DTOs。

public class Caller{
  Functional fun = new Functional(childDto1 ,childDto1 , ....childDto7 );
  fun.setChildDto8(childDtoValue8);
  fun.setChildDto9(childDtoValue9);
  fun.setChildDto10(childDtoValue10);
  ...
  ...
  fun.setChildDto30(childDtoValue30);


}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接