如何正确地重构这个?

时间:2010-03-07 20:40:19

标签: java oop refactoring

我很难找到正确重构此代码的方法,以便尽可能少的重复代码,我有几个像这样的方法(伪代码):

public List<Something> parseSomething(Node n){
  List<Something> somethings = new ArrayList<Something>();
  initialize();
  sameCodeInBothClasses();
  List<Node> nodes = getChildrenByName(n, "somename");
  for(Node n:nodes){
    method();
    actionA();
    somethings.add(new Something(actionB());
  }
  return somethings;
}

方法sameCodeInBothClasses()在所有类中都是相同的,但它不同的地方是循环actionA()的内容,它还为不同类型的List添加了一个元素。

我应该在循环内部的不同部分使用策略模式吗?

返回值怎么样(列表的类型不同),如果方法只返回List<Object>,那么我会转换为适当的类型?我应该通过我想要作为参数返回的类吗?

4 个答案:

答案 0 :(得分:1)

适用的设计模式是Template Method,而不是策略。

关于不同类型的项目,我会首先尝试对parseSomething进行泛化,如下所示:

public <T> List<T> parseSomething(Node n){
  List<T> somethings = new ArrayList<T>();
  initialize();
  sameCodeInBothClasses();
  List<Node> nodes = getChildrenByName(n, "somename");
  for(Node n:nodes){
    method();
    actionA();
    somethings.add(new T(actionB());
  }
  return somethings;
}

但这可能不适合你。您可能需要将泛型参数移动到类级别。

返回List<Object>将无效,因为通用集合不变:for 任何两种不同类型Type1Type2List<Type1>既不是子类型也不是 List<Type2>的超类型(即使Type1Type2相关,即一个是另一个的子类型!)。有关详细信息,请参阅an earlier answer of mine

因此,如果所有其他方法都失败了,快速而肮脏的解决方案确实会使用非通用的List

答案 1 :(得分:1)

如果你这样写:

public List<T> parseGeneric(Node n) {
  List<T> result = new ArrayList<T>();
  initialize();
  sameCodeInBothClasses();
  List<Node> nodes = getChildrenByName(n, "somename");
  for(Node n:nodes){
    method();
    actionA();
    result.add(new T(actionB()));
  }
  return result;
}

并将其作为

调用
List<Something> somethings = parseGeneric(aSomething);

如果没有可用的定义,很难说所有这些其他方法,但我相信你应该能够摆脱上述类似的事情。

答案 2 :(得分:1)

我的第一个想法是在一个抽象基类中声明parseSomething,每个类声明为abstract并在子类中实现的方法不同。创建Something实例的内联代码需要转换为工厂方法。

问题是parseSomething的签名需要返回不同类型的概念;例如List<Something>List<SomethingElse>。一种方法是识别常见的超类型并返回类型List<? extends SomeSuper>。另一种方法是在每个叶类中创建具有所需签名的parseXxx方法,并将它们委托给基类中的protected List<? extends SomeSuper> doParse(...)方法。

答案 3 :(得分:0)

我为方法actionA和actionB创建一个Action接口。然后是一个带有方法parseSomething的Parser类:

public List parseSomething(Node n, Action a) {
  List something = new ArrayList();
  initialize();
  samecode();
  List<Node> nodes = getChildrenByName(n, "name");
  for(Node n: nodes) {
      a.actionA();
      somethings.add(new Something(a.actionB()));
  }
  return somethings;
}