首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >面向对象思维

面向对象思维
EN

Stack Overflow用户
提问于 2016-04-27 17:16:02
回答 1查看 176关注 0票数 0

每当我认为我对OOP有了一些信心,我就会突然被一些预先的例子咬了。就像鲍勃叔叔在这个非常伟大的文章中一样,他使用了下面的类,这是他的kata的例子。

代码语言:javascript
复制
 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 {
  }
}

我有以下疑问:

  1. 为什么静态助手方法wrap
  2. 为什么InvalidArgument类是嵌套和静态的?
  3. 为什么我们甚至需要初始化这个类,因为它只是一个算法,并且可以在没有任何实例变量的情况下操作,为什么我们需要它的100个实例(例如)?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-04-27 20:53:53

  1. 为什么静态助手方法包装?

没有特别好的理由--我认为这是一种主观判断:

代码语言:javascript
复制
WordWrapper.wrap("foo", 5);

代码语言:javascript
复制
new WordWrapper(5).wrap("foo");

(我同意这一点)。当代码感觉非常重复时,我倾向于添加这样的方法。

然而,静态表单可能会导致隐藏的问题:在循环中调用它会导致创建许多不必要的WordWrapper实例,而非静态表单只是创建一个并重用它。

  1. 为什么InvalidArgument类是嵌套和静态的?

嵌套它的含义是,它只用于报告WordWrapper中方法的无效参数。例如,如果某个与数据库相关的类抛出一个WordWrapper.InvalidArgument实例,那就没有什么意义了。

请记住,为了方便起见,您可以将其引用为InvalidArgument (如果适当导入);您仍然在使用some.packagename.WordWrapper.InvalidArgument,因此它在其他类中的使用没有语义意义。

如果您希望在其他类中使用它,则不应该嵌套它。

至于为什么static:有两个原因我可以想到(这是同一枚硬币的不同方面):

  1. 它不需要是非静态的。非静态嵌套类称为内部类.它与创建它的包含类的实例有关;在某种程度上,内部类中的数据与外部类中的数据相关。 这实际上意味着,在创建外部类时,有一个对传递给内部类的外部类的隐藏引用。如果您从来不需要引用这个实例,那么就让它是静态的,这样引用就不会被传递。这就像删除未使用的方法参数一样:如果不需要它,就不要传递它。
  2. 持有此引用会产生意想不到的后果。(我将此作为单独的一点,因为前一点提到了对参考或不参考的逻辑要求/设计,而这是指保留这一提法的实际影响)。 与保存任何引用一样,如果您有对内部类实例的引用,则使其引用的所有内容都不符合垃圾收集的条件,因为它仍然是可访问的。根据如何使用内部类的实例,这可能导致内存泄漏。该类的静态版本不存在此问题,因为没有引用:当清除了所有InvalidArgument实例时,可以对Wrapper进行引用。 另一个结果是InvalidArgument的契约无效:ThrowableInvalidArgument的一个超类,它实现了Serializable,这意味着InvalidArgument也实现了Serializable。然而,WordWrapper不是Serializable。因此,由于对InvalidArgument的非空引用,非静态WordWrapper的序列化将失败。 这两个问题的简单解决方案是使嵌套类static;作为一种防御策略,应该使所有嵌套类都是静态的,除非您确实不需要它们。

  1. 为什么我们甚至需要初始化这个类,因为它只是一个算法.

问得好。这与您的第一个问题有关:您可以只使用静态助手方法,并删除实例方法和状态。

在丢弃实例方法之前,实例方法优于静态方法。

显而易见的是,您可以在实例中存储状态,例如length。这允许您向wrap传递更少的参数,这可能会减少代码的重复性;我认为它的效果有点像部分计算。(您也可以将状态存储在静态变量中,但全局可变状态是一种皇家状态,这是另一回事)。

静态方法是紧密耦合的:使用WordWrapper的类与特定的单词包装实现紧密结合。

出于许多目的,一个实现可能是可以的。但是,几乎总是有至少两个实现(生产和测试实现)的情况。

因此,下面的内容与一个实现紧密地联系在一起:

代码语言:javascript
复制
void doStuffWithAString(String s) {
  // Do something....
  WordWrapper.wrap(s, 100);
  // Do something else ....
}

可以在运行时提供以下实现:

代码语言:javascript
复制
void doStuffWithAString(WordWrapper wrapper, String s) {
  // Do something....
  wrapper.wrap(s);
  // Do something else ....
}

它使用wrapper作为策略

现在,您可以选择用于特定情况的单词包装算法(例如,一种算法适用于英语,而另一种算法对中文更有效-也许,我不知道,这只是一个例子)。

或者,对于一个测试,您可以为只返回参数的测试注入一个模拟实例--这允许您在不同时测试WordWrapper实现的情况下测试WordWrapper

但是,随着灵活性的到来,开销越来越大。静态方法更简洁。对于非常简单的方法,静态方法很可能是可行的;随着方法变得更加复杂(而且,特别是在测试用例中,为获得对测试用例很重要的特定输出而提供的输入变得越来越困难),实例方法表单将成为一个更好的选择。

最终,没有硬性的规则可供使用。注意这两种情况,并注意在给定的情况下哪种方法最有效。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36896592

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档