Java 如何正确地重构它?

Java 如何正确地重构它?,java,oop,refactoring,Java,Oop,Refactoring,我很难找到正确重构此代码的方法,以便尽可能少地重复代码,我有两种类似的方法(伪代码): 公共列表(节点n){ List somethings=new ArrayList(); 初始化(); samecodeinboth类(); 列表节点=getChildrenByName(n,“somename”); 用于(节点n:节点){ 方法(); 行动a(); 添加(新事物(actionB()); } 回报一些东西; } 方法sameCodeInBothClasses()在所有类中都是相同的,但不同之处

我很难找到正确重构此代码的方法,以便尽可能少地重复代码,我有两种类似的方法(伪代码):

公共列表(节点n){
List somethings=new ArrayList();
初始化();
samecodeinboth类();
列表节点=getChildrenByName(n,“somename”);
用于(节点n:节点){
方法();
行动a();
添加(新事物(actionB());
}
回报一些东西;
}
方法
sameCodeInBothClasses()
在所有类中都是相同的,但不同之处在于for循环
actionA()
中出现了什么,并且它还向不同类型的列表中添加了一个元素

我应该为循环中的不同部分使用策略模式吗


返回值(列表的类型不同)如何?方法是否只返回我将转换为适当类型的
list
?是否传递我要作为参数返回的类?

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

关于不同类型的项目,我会先尝试泛化
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;
}
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;
}
公共列表(节点n){
List somethings=new ArrayList();
初始化();
samecodeinboth类();
列表节点=getChildrenByName(n,“somename”);
用于(节点n:节点){
方法();
行动a();
添加(新的T(actionB());
}
回报一些东西;
}
但这可能不会立即对您起作用。您可能需要将泛型参数移动到类级别

返回
List
将不起作用,因为泛型集合是不变的:for 任何两种不同的类型
Type1
Type2
List
既不是子类型,也不是子类型
List
的超类型(即使
Type1
Type2
是相关的,即其中一个是另一个的子类型!)。有关此项的详细信息,请参阅


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

,如果您这样编写:

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;
}
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;
}
公共列表解析通用(节点n){
列表结果=新建ArrayList();
初始化();
samecodeinboth类();
列表节点=getChildrenByName(n,“somename”);
用于(节点n:节点){
方法();
行动a();
添加(新的T(actionB());
}
返回结果;
}
并将其作为

List<Something> somethings = parseGeneric(aSomething);
List something=parseGeneric(aSomething);

在没有定义的情况下,很难说这些方法都是零散的,但我相信您应该能够摆脱上述情况。

我将为方法actionA和actionB创建一个操作接口。然后是一个具有方法parseSomething的解析器类:

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;
}
公共列表(节点n,动作a){
列出某物=新的ArrayList();
初始化();
samecode();
列表节点=getChildrenByName(n,“名称”);
用于(节点n:节点){
a、 行动a();
添加(新的东西(a.actionB());
}
回报一些东西;
}

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


问题是,
parseSomething
的签名需要返回概念上不同的类型;例如,
List
List
相比。一种方法是识别一个常见的超类型,并使返回类型
Listdo方法
sameCodeInBothClasses()
method()
actionA()
会产生任何副作用吗?换句话说,这个解析方法不仅仅是解析给定节点中的内容吗?谢谢,这很好,而且我还使用了策略模式,所以for循环中唯一发生的事情就是genericParser.doTheStuff(),其中有一个具体的解析器(genericParser接口的实现)是在运行时传递的。我对这个解决方案很满意,因为不再有重复的代码。