优先使用私有静态方法而不是实例方法

时间:2019-05-12 19:48:59

标签: java oop

我正面临一个奇怪的情况。我实际上是第一次尝试JUnit测试。多年以来,我一直被告知静态方法不好(在某些情况下除外)。

但是

我发现在类中包含一些私有静态方法真的很好。主要原因是我可以控制进入方法的所有内容:我知道我将只能控制和更改参数。

任何例子都是微不足道的,实际上,这只是“防止自己在错误的情况下对错误的对象做错事的一种方法”,也许是因为我忘记了一个对象必须从方法执行的开始到结束都是一样的。就像封装一样。

所以,我要解释的是让我这样思考的最后一种情况:

class Graph {
   private Set<Edge> edges;

   // {...}

   public void newEdge(Edge e) {
      edges.add(e);
      edges = simplify(edges);
   }

   private static Set<Edge> simplify(Set<Edge> input) {
      // do something
      return output;
   }
}

不是吗?

private static Set<Edge> simplify(Set<Edge> input) {
   // do something
   return output;
}

更安全
private void simplify(Set<Edge> input) {
   // do something
   this.edges = output;
}

请告诉我我是否生气。非常感谢

2 个答案:

答案 0 :(得分:1)

并不是说静态方法不好,只是因为它们有特定的用途。

首先,我们谈论的是私有方法,因此,类外的任何代码都不常调用它。因此,只有该类的开发人员才能编写代码来调用它。这意味着它不太可能被错误地调用。

此外,对类的测试应验证其是否按照预期的方式执行。

第二,静态方法无法访问对象内部的实例变量。因此,如果该方法的目的是读取或修改实例变量,则它不能是静态的。

如果该方法正在执行的计算在变量的内部变量之间是通用的,并且该公共静态方法希望为外部调用者执行相同的服务,则该方法应为静态。但是,如果不是这种情况,则不必是静态的。

编辑:例如:

如果您不需要外部进行简化:

class Graph {
    private Set<Edge> edges;

    // {...}

    public void newEdge(Edge e) {
        edges.add(e);
        simplify();
    }

    private void simplify() {
        // use this.edges as your input
        // do something
        // set the value of your output to this.edges
    }
}

另一项修改

  

从方法的执行开始到结束,对象必须相同

如果您担心多线程环境中的一致性,则需要使用适当的线程同步方法-不要只依赖在方法末尾修改对象。

答案 1 :(得分:1)

根据我的评论(如@Jason所述),静态方法也不错,只是在某些情况下它们更适合。例如,暴露一个自包含的功能通常是使静态方法与众不同的地方。

这意味着您将需要自己提供参数,例如您的simplify方法。这实际上并没有扩大规模,如果您有一个Graph对象,那么simplify的行为将是该对象公开的东西。

这是依赖注入开始起作用的原因,因为它可以使您的测试更易于构建。因此,在您的情况下,您将拥有某种东西:

class Graph {
    private Set<Edge> edges;

    public Graph(Set<Edge> edges) {
        this.edges = ...
    }
}

诸如此类的事情将使您可以创建边缘的模拟列表,然后使用该列表执行测试。