Java 重构:消除构造函数中的重复
我似乎缺少足够的咖啡来让我清楚地看到下面的问题 假设我有一个包含两个构造函数和几个字段的类。一个构造函数是无参数构造函数,一个字段依赖于另一个字段。另一个构造函数为它的一个字段接受一个注入值。例如:Java 重构:消除构造函数中的重复,java,refactoring,Java,Refactoring,我似乎缺少足够的咖啡来让我清楚地看到下面的问题 假设我有一个包含两个构造函数和几个字段的类。一个构造函数是无参数构造函数,一个字段依赖于另一个字段。另一个构造函数为它的一个字段接受一个注入值。例如: public class Practice { private final int n; private final char c; private final Map<String, String> m; private final Set<Str
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;
}
}
公共课堂实践{
私人终审法院;
私人最终字符c;
私人最终地图m;
私人终场;
公共实践(){
这个。n=0;
this.c='a';
this.m=新的HashMap();
this.s=m.keySet();
}
公众执业(组别s){
这个。n=0;
this.c='a';
this.m=新的HashMap();
这个.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;
}
公共实践(){
这(new HashMap(),new HashMap().keySet());
}
公众执业(组别s){
这(新的HashMap(),s);
}
私人执业(int n,char c,Map m,Set s){
这个。n=0;
this.c='a';
这个,m=m;
这个.s=s;
}
当然,这会失败,因为无参数构造函数会创建两个独立的映射,而不是一个。对于初始版本,您可以从默认构造函数传递一个
null
,然后在设置s
时检查null
:
公共课堂实践{
私人终审法院;
私人最终字符c;
私人最终地图m;
私人终场;
公共实践(){
这个(空);
}
公众执业(组别s){
这个。n=0;
this.c='a';
this.m=新的HashMap();
this.s=null==s?m.keySet():s;
}
}
同样,可以更新包含3个构造函数的版本:
公共实践(){
这个(空);
}
公众执业(组别s){
这(0,'a',new HashMap(),s);//因为所有args构造函数都是私有的
}
私人执业(int n,char c,Map m,Set s){
这个,n=n;
这个.c=c;
这个,m=m;
this.s=null==s?m.keySet():s;
}
如果一个参数依赖于另一个参数,您可以通过添加额外的构造函数来解决问题。在这种情况下,私人执业(地图)
公共实践(){
这个(新的HashMap());
}
公众执业(组别s){
这(新的HashMap(),s);
}
私人执业(地图){
这个(map,map.keySet());
}
私人执业(地图、地图、集合s){
这个。n=0;
this.c='a';
这个.m=映射;
这个.s=s;
}
您可以在将变量定义为成员时初始化变量。在构造函数中,您可以严格地初始化那些在初始化后可以保存不同值的变量
另请注意:由于n
和c
是原语,因此它们适合作为静态的
,因为它们也被标记为最终的
。这对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;
}
}
公共课堂实践{
私有静态最终整数n=0;
私有静态最终字符c='a';
私有最终映射m=新HashMap();
私人终场;
公共实践(){
this.s=m.keySet();
}
公众执业(组别s){
这个.s=s;
}
}
最后,没有必要消除每一个和任何重复的代码。这方面的规则各不相同,尽管我通常遵循三个规则,或者当重复的块很大时。只需一句话:
null==s
通常是一种C/C++风格,以防止意外分配条件,如s=null代码>。在java中,语言设计无法实现这一点。@JoopEggen,如果s
属于Boolean
类型,那么即使是语言设计也无法对抗NPEBoolean ok=true;System.out.println((ok=null)?“ok”:“Bad”)代码>:我在90-s的中间发现了这个习惯,它就像一个安全措施,使用左边的文字和右边的“代码> ==< /代码>比较”,因为文字不能被分配。是的,对我来说,这是一种来自于允许的C/C++函数的习惯。这是一个不自然的公式(“x等于3”与“3等于x”),所以在使用java时,我通常不使用它。我想知道java代码样式检查器是否适合您的样式。@k314159。在尤达以上的情况下,似乎一点也不有害
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;
}
}