具有两个输出的重构方法

时间:2014-05-23 15:15:57

标签: java groovy functional-programming refactoring

背景

我在代码中遇到了很多方法我负责重构,遵循以下一般模式:

  1. 采取综合输入
  2. 根据某些标准查找复合材料的子项
  3. 从复合中删除子项,但要跟踪它们
  4. 返回更新的合成并将删除的子项追加到输出参数集合
  5. 在代码中它看起来像这样:

    public Composite trim(Composite composite, List<Child> removed){
    
      for (Child child : composite.getChildren()){
    
        if (criterion(child)){
          composite.remove(child);
          removed.add(child);
        }
      }
    }
    

    这里有许多代码气味,但我想解决的是如何将其重构为不可变代码,因此不会写入输出参数。

    可能但不那么优雅的解决方案

    public Map<String, Object> trim(Composite composite){
    
      final List<Child> removableChildren = filter(composite);
      final Composite trimmed = copyCompositeWithoutChildren(composite, removableChildren);
    
      return wrapInMap(removableChildren, trimmed);
    }
    

    问题

    有没有更简洁的方法来实现这一点,例如,在groovy或Java 8中使用诸如收集或拼接之类的函数式编程方法可能会在Java pre-8中提供更好的,尽管更详细的方法?任何一种语言的例子都将受到高度赞赏。

    修改

    第二种可能的解决方案

    Steinar's answer的启发:使用策略模式。

    public interface FilterStrategy {
      List<Child> filter(List<Child> children);
    }
    
    public interface RemovalResponseStrategy {
      void respond(List<Child> removedChildren);
    }
    
    public class CompositeTrimmer {
    
      private final FilterStrategy filterStrategy;
      private final RemovalResponseStrategy removalResponseStrategy;
    
      public Composite trim(final Composite composite){
    
        final List<Child> removableChildren = 
          filterStrategy.filter(composite.getChildren());
    
        final Composite trimmed = 
          copyCompositeWithoutChildren(composite, removableChildren);
    
        removalResponseStrategy.respond(removableChildren);  
    
        return trimmed;
      }
    }
    

1 个答案:

答案 0 :(得分:1)

你没有说你有什么样的自由来改变Composite类或者哪种方法 已有。所以我刚刚做了些什么。它可能会被改装成你所拥有的 很容易。

更多的常规解决方案是这样的:

def trim(Composite composite, Closure removeCriterion) {
    List<Child> removedChildren = composite.children.findAll(removeCriterion)
    List<Child> remainingChildren = composite.children - removedChildren
    Composite filteredComposite = new Composite(children: remainingChildren)
    [filteredComposite, removedChildren]
}

您不需要将标准指定为参数,但我有点喜欢它。使代码更多 柔性的。

基本上,首先找到要移除的子项,然后与剩余的子项一起创建一个新的复合。 最后返回两个输出的列表。由于groovy支持列表中的多个赋值,所以 返回多个输出的简单方法。

使用CompositeChild的虚拟实现测试了解决方案。

用法和测试:

def test() {
    Composite composite = new Composite(children: [
            new Child(name: 'Angus'),
            new Child(name: 'Steinar'),
            new Child(name: 'Erik'),
            new Child(name: 'William'),
    ])

    def (Composite filteredComposite, List<Child> removedChildren) =
            trim(composite) {
                Child child -> child.name > 'H'
            }

    assert filteredComposite.children == [new Child(name: 'Angus'), new Child(name: 'Erik')]
    assert removedChildren == [new Child(name: 'Steinar'), new Child(name: 'William')]
}

@ToString(includePackage = false)
@EqualsAndHashCode
class Child {
    String name
}

@ToString(includePackage = false)
@EqualsAndHashCode
class Composite {
    List<Child> children
}