重构:构造函数中的重复代码删除

huangapple go评论60阅读模式
英文:

Refactoring: removal of duplication in constructor

问题

我似乎缺乏足够的咖啡来清楚地看待以下问题。

想象一下,我有一个带有两个构造函数和多个字段的类。一个构造函数是无参构造函数,一个字段依赖于另一个字段。另一个构造函数为其字段之一接受一个注入值。示例:

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;
}

当然,这个尝试失败了,因为无参构造函数创建了两个单独的Map,而不是一个。

英文:

I seem to be lacking enough coffee to make me see the following problem clearly.

Imagine I have a class with two constructors and several fields. One constructor is a no-arg constructor and one field depends on another. The other constructor takes an injected value for one of its fields. Example:

public class Practice {
    private final int n;
    private final char c;
    private final Map&lt;String, String&gt; m;
    private final Set&lt;String&gt; s;

    public Practice() {
        this.n = 0;
        this.c = &#39;a&#39;;
        this.m = new HashMap&lt;&gt;();
        this.s = m.keySet();
    }
    
    public Practice(Set&lt;String&gt; s) {
        this.n = 0;
        this.c = &#39;a&#39;;
        this.m = new HashMap&lt;&gt;();
        this.s = s;
    }
}

My question: how do I remove the duplication of code between the two constructors?

First failed attempt:

public Practice() {
    this(new HashMap&lt;&gt;(), new HashMap&lt;&gt;().keySet());
}

public Practice(Set&lt;String&gt; s) {
    this(new HashMap&lt;&gt;(), s);
}

private Practice(int n, char c, Map&lt;String, String&gt; m, Set&lt;String&gt; s) {
    this.n = 0;
    this.c = &#39;a&#39;;
    this.m = m;
    this.s = s;
}

Of course, this fails because the no-args constructor creates two separate Maps instead of one.

答案1

得分: 3

在某些情况下,一个参数取决于另一个参数,您可以通过添加额外的构造函数来解决这个问题。在这种情况下 private Practice(Map&lt;String,String&gt; map)

public Practice() {
    this(new HashMap&lt;&gt;());
}

public Practice(Set&lt;String&gt; s) {
    this(new HashMap&lt;&gt;(), s);
}

private Practice(Map&lt;String,String&gt; map) {
    this(map, map.keySet());
}

private Practice(Map&lt;String,String&gt; map, Set&lt;String&gt; s) {
    this.n = 0;
    this.c = &#39;a&#39;;
    this.m = map;
    this.s = s;
}
英文:

In cases where one argument depends on another argument you can solve the problem by adding an additional constructor. In this case private Practice(Map&lt;String,String&gt; map)

public Practice() {
    this(new HashMap&lt;&gt;());
}

public Practice(Set&lt;String&gt; s) {
    this(new HashMap&lt;&gt;(), s);
}

private Practice(Map&lt;String,String&gt; map) {
    this(map, map.keySet());
}

private Practice(Map&lt;String,String&gt; map, Set&lt;String&gt; s) {
    this.n = 0;
    this.c = &#39;a&#39;;
    this.m = map;
    this.s = s;
}

答案2

得分: 3

你可以在定义成员变量的同时初始化它们。在构造函数中,你可以只初始化那些在初始化后可能会持有不同值的变量。

另外注意:由于 nc 是基本数据类型,它们适合被声明为 static,因为它们也被标记为 final。但对于 m 来说,情况不同。

最后,没有必要消除代码中的每一个重复部分。关于这一点的规则各不相同,但通常我遵循三次重复原则,或者当重复的代码块很大时才进行重构。

英文:

You can just initialize variables as you define them as members. In your constructor you can stick to initializing strictly those variables that can hold a different value after initialization.

Also note: Since n and c are primitives they are suitable candidates to be static, since they are also tagged final. This does not hold true for m.

public class Practice {
    private static final int n = 0;
    private static final char c = &#39;a&#39;;
    private final Map&lt;String, String&gt; m = new HashMap&lt;&gt;();
    private final Set&lt;String&gt; s;

    public Practice() {
        this.s = m.keySet();
    }
    
    public Practice(Set&lt;String&gt; s) {
        this.s = s;
    }
}

Lastly - it is not necessary to kill each and any duplication of code. The rules on this vary, though I usually follow the rule-of-three or when the duplicated chunks are large.

答案3

得分: 1

对于初始版本,您可以从默认构造函数传递一个 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;
    }
}

类似地,具有三个构造函数的版本可以进行更新:

public Practice() {
    this(null);
}

public Practice(Set<String> s) {
    this(0, 'a', new HashMap<>(), s); // 由于所有参数构造函数是私有的
}

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;
}
英文:

For the initial version, you could pass a null from the default constructor and then check for null when setting s:

public class Practice {
    private final int n;
    private final char c;
    private final Map&lt;String, String&gt; m;
    private final Set&lt;String&gt; s;

    public Practice() {
        this(null);
    }
    
    public Practice(Set&lt;String&gt; s) {
        this.n = 0;
        this.c = &#39;a&#39;;
        this.m = new HashMap&lt;&gt;();
        this.s = null == s ? m.keySet() : s;
    }
}

Similarly, the version with 3 constructors can be updated:

public Practice() {
    this(null);
}

public Practice(Set&lt;String&gt; s) {
    this(0, &#39;a&#39;, new HashMap&lt;&gt;(), s); // as all args constructor is private
}

private Practice(int n, char c, Map&lt;String, String&gt; m, Set&lt;String&gt; s) {
    this.n = n;
    this.c = c;
    this.m = m;
    this.s = null == s ? m.keySet() : s;
}

huangapple
  • 本文由 发表于 2020年10月27日 23:42:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/64557928.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定