【问题标题】:Creating static utility methods should not be overused however ? how to avoid it? [closed]但是,不应过度使用创建静态实用程序方法?如何避免? [关闭]
【发布时间】:2013-06-27 03:36:23
【问题描述】:


随着时间的推移......在 java 项目中引入了许多实用方法来完成更复杂和简单的任务。

当使用静态方法时,我们会在代码中引入紧密耦合,这会使我们的代码更难测试,尤其是在实用方法非常复杂的情况下。

我只是认为现在很难管理和测试这些实用程序。请指导我避免使用这些实用程序方法以及如何组织现有项目以删除所有 STATIC 实用程序。

你能帮我避免使用静态方法吗?

【问题讨论】:

  • 我真的不明白使用static 方法如何增加耦合并使测试变得困难。
  • @NPE:您不能模拟或覆盖静态方法。因此,使用静态方法的代码很难测试。
  • @TomAnderson 你得到的是错误的方法。静态方法是无状态的,这使得测试变得容易
  • @Bohemian:不。请再次阅读我的评论。静态方法可能很容易测试,但使用它们的代码通常不是。
  • @JensSchauder 你称之为解决方法,我称之为解决方案。有时需要一个接口来模拟。那么每个方法都应该在接口中,还是使用可以模拟非接口方法的“变通”框架?

标签: java oop static


【解决方案1】:

静态实用程序方法还不错。您可以在静态调用后面隐藏包私有策略。假设测试用例属于同一个包,这可以很容易地测试(和替换)。此外,它使代码非常易读。当然,静态实用程序方法的客户端在他们的测试中仍然只能使用一种实现。所以这里有些不灵活。

波西米亚人在谈论国家时是正确的。如果您的静态实用程序有状态说明您做错了什么。

关于您的问题:如果您想避免使用静态方法,您可以使用 spring 框架并定义您在不同上下文中使用和测试的实用程序的不同实现。然而,在这种情况下,访问这些对象并不那么方便,因为您必须首先获取对知道您的实用程序 object 的上下文的引用。

【讨论】:

  • 你错过了 Spring 的全部意义。您不需要对 Spring 上下文的引用来获取对 bean 的引用。你只需要在你需要的地方由 Spring 注入它。就像@Inject private UtilityObject utility 一样简单。
  • 是的,您可以减轻静态方法带来的痛苦,但它们仍然很糟糕。此外,Spring 绝不需要摆脱静态方法。
【解决方案2】:

拥有大量静态方法并没有错。

静态方法是(或应该是,请继续阅读)stateless,这使它们成为最容易测试的方法 - 无需设置,只需调用它们即可。

你不需要嘲笑,因为没有要处理的状态。

关于无状态,如果使用静态变量来存储状态,从技术上讲,静态方法可以是有状态的。如果是这种情况,从良好设计的角度来看,它们应该转换为使用实例变量来存储状态的实例方法,如果需要,可以使用单例模式。

【讨论】:

  • 静态、无状态的方法很容易测试。但是测试使用这些静态无状态方法的代码很困难,因为它们不容易被模拟。用可注入组件中的实例方法替换它们允许模拟组件并在测试中注入模拟。
  • 实际上在代码库中,有很多静态方法..它们正在处理对象的状态......比如将对象作为输入并返回更新的对象......在 OOP 中思考,我想将这些方法移动到类本身。
  • @JBNizet 我想我正在考虑只有一个实现的实用程序,因此注入不是必需的或有用的——这些方法只是“做无状态、无上下文的 stuuf”。不过,您的评论非常好-强调如果您的静态方法随上下文改变行为,请强烈考虑注入和实例方法。
【解决方案3】:

属于一个类的一组静态实用程序方法没有错。参见例如java.util.Collections。如果该类中在List 上运行的每个方法都将在List 接口本身中指定,则它们必须由所有子类实现。只要可以通过公共的List方法实现就没有问题。

当然,只要您开始向接口添加方法(或者在类的情况下,将方法设为公共),以便能够将功能放入静态方法而不是类本身,那么您就处于走错路了。

【讨论】:

  • 您所描述的是该语言的弱点,这可能使静态方法成为两个问题中较小的一个。但静态仍然是个问题。
  • @JensSchauder 我描述了语言的哪些弱点?
  • List 接口的方法必须由其所有实现/子类实现,这会导致代码重复或严格的继承层次结构。 Scala 特性很好地解决了这个问题,正如 Scala 的集合 API 中所演示的那样,并且可以轻松添加新的实现,尽管接口比 Java 等价物有更多的方法。
  • 郑重声明,Java 8 将具有防御者方法,允许接口具有具体方法。因此,我们将能够调用list.sort(comparator) 而不是Collections.sort(list, comparator)
  • 我同意:在您描述的情况下,模拟它们的需求很少或不存在。但不幸的是,在我过去见过的平均静态方法中,情况并非如此。
【解决方案4】:

与当前可用的其他答案相矛盾:静态方法不好!

它们确实引入了强耦合。是的,有些情况是可以接受的。是的,您可以通过使内部使用的策略可交换来为静态方法内部创建接缝。但根据经验,静态仍然很糟糕。

要回答这个问题,如何摆脱静态方法。很简单:把它们放在一个合适的对象上。所有的静电都消失了。我们改进了代码吗?还不算多。如果我们替换

callToStaticMethod()

new X().callToNoLongerStaticMethod()

我们用构造函数调用替换了静态调用,构造函数调用本质上只是另一个静态方法。但是现在你的 X 只是另一个依赖,所以你可以注入它:

class A{
    private final X x;
    A(X aX){
        x = aX;
    }
} 

注意:不需要为此使用 Spring 或任何其他框架。如果您觉得它提供了一个使用默认实现的构造函数。如果您是纯粹主义者,请为 X 引入一个接口。

在不依赖X 的实现的情况下测试A 变得简单而明显。以任何方式替换 X 也是如此。

【讨论】:

  • 好的,去告诉java API设计者他们应该删除java.util.Collectionsjava.util.Arraysjava.lang.Math,......那些认为静态方法不好的人应该被禁止使用这些:- )
  • 想象一下每次你想调用Arrays.asList(...)时都必须注入一个ArrayToListConversionStrategy
  • 谢谢@Jens:这是我一直在寻找的东西。
  • @herman 我怀疑有人会听我的。这就是为什么我更喜欢 Scala。当您尝试编写概念上干净的代码时,那里没有静态和很好的工具来避免 Java 强加给您的样板代码。 :-)
  • @JensSchauder 但是 Scala 有单例对象来提供静态方法的作用,并且单例(纯粹主义者)被视为与静态方法一样的反模式。 (免责声明:我是 Scala 新手)
猜你喜欢
  • 1970-01-01
  • 2023-04-01
  • 2014-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-25
  • 2011-06-06
相关资源
最近更新 更多