重构:删除构造函数中的重复项
Refactoring: removal of duplication in constructor
我好像是咖啡不够让我看清下面的问题
假设我有一个 class,其中包含两个构造函数和多个字段。一个构造函数是无参数构造函数,一个字段依赖于另一个字段。另一个构造函数为其其中一个字段获取注入值。示例:
public class Practice {
private final int n;
private final char c;
private final Map<String, String> m;
private final Set<String> s;
public Practice() {
this.n = 0;
this.c = 'a';
this.m = new HashMap<>();
this.s = m.keySet();
}
public Practice(Set<String> s) {
this.n = 0;
this.c = 'a';
this.m = new HashMap<>();
this.s = s;
}
}
我的问题:如何消除两个构造函数之间的重复代码?
第一次失败尝试:
public Practice() {
this(new HashMap<>(), new HashMap<>().keySet());
}
public Practice(Set<String> s) {
this(new HashMap<>(), s);
}
private Practice(int n, char c, Map<String, String> m, Set<String> s) {
this.n = 0;
this.c = 'a';
this.m = m;
this.s = s;
}
当然,这会失败,因为无参数构造函数创建了两个单独的映射而不是一个映射。
对于初始版本,您可以从默认构造函数传递一个 null
,然后在设置 s
:
时检查 null
public class Practice {
private final int n;
private final char c;
private final Map<String, String> m;
private final Set<String> s;
public Practice() {
this(null);
}
public Practice(Set<String> s) {
this.n = 0;
this.c = 'a';
this.m = new HashMap<>();
this.s = null == s ? m.keySet() : s;
}
}
同样可以更新3个构造函数的版本:
public Practice() {
this(null);
}
public Practice(Set<String> s) {
this(0, 'a', new HashMap<>(), s); // as all args constructor is private
}
private Practice(int n, char c, Map<String, String> m, Set<String> s) {
this.n = n;
this.c = c;
this.m = m;
this.s = null == s ? m.keySet() : s;
}
如果一个参数依赖于另一个参数,您可以通过添加额外的构造函数来解决问题。在这种情况下 private Practice(Map<String,String> map)
public Practice() {
this(new HashMap<>());
}
public Practice(Set<String> s) {
this(new HashMap<>(), s);
}
private Practice(Map<String,String> map) {
this(map, map.keySet());
}
private Practice(Map<String,String> map, Set<String> s) {
this.n = 0;
this.c = 'a';
this.m = map;
this.s = s;
}
您可以在将变量定义为成员时对其进行初始化。在您的构造函数中,您可以坚持严格初始化那些在初始化后可以保存不同值的变量。
另请注意:由于 n
和 c
是原语,因此它们是 static
的合适候选者,因为它们也被标记为 final
。这不适用于 m
.
public class Practice {
private static final int n = 0;
private static final char c = 'a';
private final Map<String, String> m = new HashMap<>();
private final Set<String> s;
public Practice() {
this.s = m.keySet();
}
public Practice(Set<String> s) {
this.s = s;
}
}
最后 - 没有必要删除所有重复的代码。尽管我通常遵循 rule-of-three 或当重复的块很大时,这方面的规则各不相同。
我好像是咖啡不够让我看清下面的问题
假设我有一个 class,其中包含两个构造函数和多个字段。一个构造函数是无参数构造函数,一个字段依赖于另一个字段。另一个构造函数为其其中一个字段获取注入值。示例:
public class Practice {
private final int n;
private final char c;
private final Map<String, String> m;
private final Set<String> s;
public Practice() {
this.n = 0;
this.c = 'a';
this.m = new HashMap<>();
this.s = m.keySet();
}
public Practice(Set<String> s) {
this.n = 0;
this.c = 'a';
this.m = new HashMap<>();
this.s = s;
}
}
我的问题:如何消除两个构造函数之间的重复代码?
第一次失败尝试:
public Practice() {
this(new HashMap<>(), new HashMap<>().keySet());
}
public Practice(Set<String> s) {
this(new HashMap<>(), s);
}
private Practice(int n, char c, Map<String, String> m, Set<String> s) {
this.n = 0;
this.c = 'a';
this.m = m;
this.s = s;
}
当然,这会失败,因为无参数构造函数创建了两个单独的映射而不是一个映射。
对于初始版本,您可以从默认构造函数传递一个 null
,然后在设置 s
:
null
public class Practice {
private final int n;
private final char c;
private final Map<String, String> m;
private final Set<String> s;
public Practice() {
this(null);
}
public Practice(Set<String> s) {
this.n = 0;
this.c = 'a';
this.m = new HashMap<>();
this.s = null == s ? m.keySet() : s;
}
}
同样可以更新3个构造函数的版本:
public Practice() {
this(null);
}
public Practice(Set<String> s) {
this(0, 'a', new HashMap<>(), s); // as all args constructor is private
}
private Practice(int n, char c, Map<String, String> m, Set<String> s) {
this.n = n;
this.c = c;
this.m = m;
this.s = null == s ? m.keySet() : s;
}
如果一个参数依赖于另一个参数,您可以通过添加额外的构造函数来解决问题。在这种情况下 private Practice(Map<String,String> map)
public Practice() {
this(new HashMap<>());
}
public Practice(Set<String> s) {
this(new HashMap<>(), s);
}
private Practice(Map<String,String> map) {
this(map, map.keySet());
}
private Practice(Map<String,String> map, Set<String> s) {
this.n = 0;
this.c = 'a';
this.m = map;
this.s = s;
}
您可以在将变量定义为成员时对其进行初始化。在您的构造函数中,您可以坚持严格初始化那些在初始化后可以保存不同值的变量。
另请注意:由于 n
和 c
是原语,因此它们是 static
的合适候选者,因为它们也被标记为 final
。这不适用于 m
.
public class Practice {
private static final int n = 0;
private static final char c = 'a';
private final Map<String, String> m = new HashMap<>();
private final Set<String> s;
public Practice() {
this.s = m.keySet();
}
public Practice(Set<String> s) {
this.s = s;
}
}
最后 - 没有必要删除所有重复的代码。尽管我通常遵循 rule-of-three 或当重复的块很大时,这方面的规则各不相同。