简体   繁体   English

避免对具有不同返回类型的方法进行代码重复

[英]Avoiding code duplication for methods with different return types

I have two builder classes that return a Tree and a Set respectively. 我有两个生成器类,分别返回一个Tree和一个Set The execution of the second builder is just the execution of the first builder with an extra step and a different return type. 第二个构建器的执行只是第一个构建器的执行,带有额外的步骤和不同的返回类型。 I really don't want to duplicate the same steps in two different classes, because if there is a change in the Tree -building process, I have to change code in two classes. 我真的不想在两个不同的类中重复相同的步骤,因为如果在Tree构建过程中进行了更改,则必须在两个类中更改代码。 Here are the two builders: 这是两个构建器:

public class TreeBuilder {

    private NodeHelper nodeHelper;

    public TreeBuilder(NodeHelper nodeHelper) {
        this.nodeHelper = nodeHelper;
    }

    public Tree<EquipmentDetails> buildTree() {

        Tree<EquipmentDetails> tree = new Tree<>(nodeHelper.getEquipmentDetails(nodeHelper.getModelName()));

        return buildTree(tree);
    }

    private Tree<EquipmentDetails> buildTree(Tree<EquipmentDetails> parentTree) {

        Map<String, NativeSlotDisplayLabel> childSubTypeMap = nodeHelper.getChildSubTypeMap(parentTree);

        if (CommonUtils.nullOrEmpty(childSubTypeMap))
            return parentTree;

        for (String holderCommonName : childSubTypeMap.keySet()) {

            NativeSlotDisplayLabel nativeSlotDisplayLabel = childSubTypeMap.get(holderCommonName);

            EquipmentDetails equipmentDetails = nodeHelper.constructEqptDetails(holderCommonName, nativeSlotDisplayLabel, parentTree);

            Tree<EquipmentDetails> childTree = new Tree<>(equipmentDetails);

            parentTree.addChild(childTree);

            String equipmentCommonName = equipmentDetails.getModelEquipType();

            if (equipmentCommonName == null)
                continue;

            buildTree(childTree);
        }

        return parentTree;
    }
}

The second builder uses one more dependency and returns a Set instead of a Tree : 第二个构建器使用另一个依赖项,并返回Set而不是Tree

public class FreePortsBuilder {

    private NodeHelper nodeHelper;

    private PortLabelGenerator portLabelGenerator;

    public FreePortsBuilder(NodeHelper nodeHelper, PortLabelGenerator portLabelGenerator) {
        this.nodeHelper = nodeHelper;
        this.portLabelGenerator = portLabelGenerator;
    }

    public Set<PortNameAndLabel> collectFreePorts(){

        Tree<EquipmentDetails> tree = new Tree<>(nodeHelper.getEquipmentDetails(nodeHelper.getModelName()));

        Set<PortNameAndLabel> portNameAndLabels = new HashSet<>();

        return collectFreePorts(tree, portNameAndLabels);
    }

    private Set<PortNameAndLabel> collectFreePorts(Tree<EquipmentDetails> parentTree, Set<PortNameAndLabel> portNameAndLabels) {

        Map<String, NativeSlotDisplayLabel> childSubTypeMap = nodeHelper.getChildSubTypeMap(parentTree);

        if (CommonUtils.nullOrEmpty(childSubTypeMap))
            return portNameAndLabels;

        Set<PortNameAndLabel> generatedPortNameAndLabel = portLabelGenerator.getPortNameAndLabel(childSubTypeMap, parentTree.getUserObject());

        portNameAndLabels.addAll(generatedPortNameAndLabel);

        for (String holderCommonName : childSubTypeMap.keySet()) {

            NativeSlotDisplayLabel nativeSlotDisplayLabel = childSubTypeMap.get(holderCommonName);

            EquipmentDetails equipmentDetails = nodeHelper.constructEqptDetails(holderCommonName, nativeSlotDisplayLabel, parentTree);

            Tree<EquipmentDetails> childTree = new Tree<>(equipmentDetails);

            parentTree.addChild(childTree);

            String equipmentCommonName = equipmentDetails.getModelEquipType();

            if (equipmentCommonName == null)
                continue;

            collectFreePorts(childTree, portNameAndLabels);
        }

        return portNameAndLabels;
    }
}

I am looking for a way to avoid the duplication. 我正在寻找一种避免重复的方法。 Any suggestions? 有什么建议么?

FreePortsBuilder is doing two things at the same time: FreePortsBuilder同时执行两项操作:

  1. Building a Tree : as you know, this is identical to what TreeBuilder does. 构建Tree :如您所知,这与TreeBuilder作用相同。
  2. Building a Set<PortNameAndLabel> , where each PortNameAndLabel appears to be associated with a node or child (which is itself a Tree ) in the final Tree . 构建一个Set<PortNameAndLabel> ,其中每个PortNameAndLabel似乎与最终Tree的节点或子代(本身就是Tree )相关联。

Instead of doing the above two things simultaneously, do them sequentially. 与其同时执行上述两件事,不如依次执行它们。 That is, in FreePortsBuilder , first use TreeBuilder to build the Tree , then traverse this Tree to construct the Set<PortNameAndLabel> . 也就是说,在FreePortsBuilder首先使用TreeBuilder来构建Tree然后遍历此Tree来构建Set<PortNameAndLabel> One way to do that is the following (I assume that your Tree class has a method like getChildren() that returns a List<Tree<EquipmentDetails>> ). 一种实现方法如下(我假设您的Tree类具有类似getChildren()的方法,该方法返回List<Tree<EquipmentDetails>> )。

First, allow a client to obtain a TreeBuilder 's NodeHelper by adding a getter: 首先,允许客户端通过添加getter获得TreeBuilderNodeHelper

public class TreeBuilder {
  private NodeHelper nodeHelper;

  public NodeHelper getNodeHelper() {
    return this.nodeHelper;
  }

  ...
}

Then, inject a TreeBuilder instead of a NodeHelper into FreePortsBuilder ( FreePortsBuilder can use the NodeHelper that is in the TreeBuilder , because of the getter that we just added): 然后,注入TreeBuilder代替NodeHelperFreePortsBuilderFreePortsBuilder可以使用NodeHelper是在TreeBuilder ,因为我们刚才添加的吸气剂):

public class FreePortsBuilder {
  private TreeBuilder treeBuilder;
  private PortLabelGenerator portLabelGenerator;

  public FreePortsBuilder(TreeBuilder treeBuilder, PortLabelGenerator portLabelGenerator) {
    this.treeBuilder = treeBuilder;
    this.portLabelGenerator = portLabelGenerator;
  }

  public Set<PortNameAndLabel> collectFreePorts() {
    Tree<EquipmentDetails> tree = treeBuilder.buildTree();
    return collectFreePorts(tree);
  }

  private Set<PortNameAndLabel> collectFreePorts(Tree<EquipmentDetails> tree) {
    Set<PortNameAndLabel> portNameAndLabels = new HashSet<>();

    for (Tree<EquipmentDetails> child : tree.getChildren()) {
      Map<String, NativeSlotDisplayLabel> childSubTypeMap =
          treeBuilder.getNodeHelper().getChildSubTypeMap(child);

      if (CommonUtils.nullOrEmpty(childSubTypeMap))
        continue;

      Set<PortNameAndLabel> generatedPortNameAndLabel =
          portLabelGenerator.getPortNameAndLabel(childSubTypeMap, child.getUserObject());

      portNameAndLabels.addAll(generatedPortNameAndLabel);
    }

    return portNameAndLabels;
  }
}

Now, FreePortsBuilder can truly make use of the TreeBuilder implementation, and the code duplication is removed. 现在, FreePortsBuilder可以真正利用TreeBuilder实现,并且删除了重复的代码。

You can use Strategy design pattern or Template Method here. 您可以在此处使用策略设计模式模板方法 You have an algorithm here where only certain steps change (collectFreePorts & buildTree). 您这里有一个算法,其中仅某些步骤会发生变化(collectFreePorts和buildTree)。

If you cannot use inheritance, you can use a similar solution to this: https://softwareengineering.stackexchange.com/questions/187872/template-method-within-one-class-without-subclasses-or-inheritance 如果您不能使用继承,则可以使用类似的解决方案: https : //softwareengineering.stackexchange.com/questions/187872/template-method-within-one-class-without-subclasses-or-inheritance

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM