每当我认为我对OOP有了一些信心,我就会突然被一些预先的例子咬了。就像鲍勃叔叔在这个非常伟大的文章中一样,他使用了下面的类,这是他的kata的例子。
public class WordWrapper {
private int length;
public WordWrapper(int length) {
this.length = length;
}
public static String wrap(String s, int length) {
return new WordWrapper(length).wrap(s);
}
public String wrap(String s) {
if (length < 1)
throw new InvalidArgument();
if (s == null)
return "";
if (s.length() <= length)
return s;
else {
int space = s.indexOf(" ");
if (space >= 0)
return breakBetween(s, space, space + 1);
else
return breakBetween(s, length, length);
}
}
private String breakBetween(String s, int start, int end) {
return s.substring(0, start) +
"\n" +
wrap(s.substring(end), length);
}
public static class InvalidArgument extends RuntimeException {
}
}我有以下疑问:
wrapInvalidArgument类是嵌套和静态的?发布于 2016-04-27 20:53:53
没有特别好的理由--我认为这是一种主观判断:
WordWrapper.wrap("foo", 5);比
new WordWrapper(5).wrap("foo");(我同意这一点)。当代码感觉非常重复时,我倾向于添加这样的方法。
然而,静态表单可能会导致隐藏的问题:在循环中调用它会导致创建许多不必要的WordWrapper实例,而非静态表单只是创建一个并重用它。
InvalidArgument类是嵌套和静态的?嵌套它的含义是,它只用于报告WordWrapper中方法的无效参数。例如,如果某个与数据库相关的类抛出一个WordWrapper.InvalidArgument实例,那就没有什么意义了。
请记住,为了方便起见,您可以将其引用为InvalidArgument (如果适当导入);您仍然在使用some.packagename.WordWrapper.InvalidArgument,因此它在其他类中的使用没有语义意义。
如果您希望在其他类中使用它,则不应该嵌套它。
至于为什么static:有两个原因我可以想到(这是同一枚硬币的不同方面):
InvalidArgument实例时,可以对Wrapper进行引用。
另一个结果是InvalidArgument的契约无效:Throwable是InvalidArgument的一个超类,它实现了Serializable,这意味着InvalidArgument也实现了Serializable。然而,WordWrapper不是Serializable。因此,由于对InvalidArgument的非空引用,非静态WordWrapper的序列化将失败。
这两个问题的简单解决方案是使嵌套类static;作为一种防御策略,应该使所有嵌套类都是静态的,除非您确实不需要它们。问得好。这与您的第一个问题有关:您可以只使用静态助手方法,并删除实例方法和状态。
在丢弃实例方法之前,实例方法优于静态方法。
显而易见的是,您可以在实例中存储状态,例如length。这允许您向wrap传递更少的参数,这可能会减少代码的重复性;我认为它的效果有点像部分计算。(您也可以将状态存储在静态变量中,但全局可变状态是一种皇家状态,这是另一回事)。
静态方法是紧密耦合的:使用WordWrapper的类与特定的单词包装实现紧密结合。
出于许多目的,一个实现可能是可以的。但是,几乎总是有至少两个实现(生产和测试实现)的情况。
因此,下面的内容与一个实现紧密地联系在一起:
void doStuffWithAString(String s) {
// Do something....
WordWrapper.wrap(s, 100);
// Do something else ....
}可以在运行时提供以下实现:
void doStuffWithAString(WordWrapper wrapper, String s) {
// Do something....
wrapper.wrap(s);
// Do something else ....
}它使用wrapper作为策略。
现在,您可以选择用于特定情况的单词包装算法(例如,一种算法适用于英语,而另一种算法对中文更有效-也许,我不知道,这只是一个例子)。
或者,对于一个测试,您可以为只返回参数的测试注入一个模拟实例--这允许您在不同时测试WordWrapper实现的情况下测试WordWrapper。
但是,随着灵活性的到来,开销越来越大。静态方法更简洁。对于非常简单的方法,静态方法很可能是可行的;随着方法变得更加复杂(而且,特别是在测试用例中,为获得对测试用例很重要的特定输出而提供的输入变得越来越困难),实例方法表单将成为一个更好的选择。
最终,没有硬性的规则可供使用。注意这两种情况,并注意在给定的情况下哪种方法最有效。
https://stackoverflow.com/questions/36896592
复制相似问题