在Spring应用程序中的实用类 - 我应该使用静态方法还是非静态方法?

80

设想我有一个工具类 DateUtil(参见以下代码)。为了使用这个方法,调用者需要使用 DateUtils.getDateAsString(aDate)。是否应该移除静态修饰符,将 DateUtil 变为 Spring Bean(参见 DateUtilsBean),并将其注入到调用类中,还是像现在一样保持不变?

我能看到使用静态方法的一个缺点是在模拟方面可能会出现问题,可参考如何模拟静态方法?

public class DateUtils {

    public static String getDateAsString(Date date) {       
        String retValue =  "" // do something here using date parameter
        return retValue;
    }
}

Spring Bean版本

@Component
public class DateUtilsBean {

    public String getDateAsString(Date date) {      
        String retValue =  "" // do something here using date parameter
        return retValue;
    }
}
5个回答

54

我不这么认为。DateUtils类听起来像是一个纯粹的实用工具类,它没有任何副作用,只是处理输入参数。那种功能可能最好保留在静态方法中。我不认为你会想要模拟日期辅助方法。


15
同意。仅仅因为任何东西都可以被设置为Spring bean,不意味着所有东西都应该被设置为Spring bean。 - David J. Liszewski
9
如果静态方法读取驱动我的应用程序的配置文件,我希望能够模拟这种行为。想象一下:你想进行功能测试,但不想成为“配置工厂”。如果它是单例模式,那么我可以更容易地模拟该方法并从代码中驱动我的测试。 不过,使用PowerMock也可以模拟静态方法。 - uthomas
7
可能是过度设计,但将它制作成可注入的bean可以更轻松地对依赖类进行单元测试。如果它实现了一个接口,那么测试将变得更加容易。 - Behrang
1
一个重要的用例是时间。考虑使用Java 8的时钟作为bean来避免与时间相关的不稳定测试。 - David W
@DavidW 是的,但那个时钟是专门为此设计的。我在编辑其他人的代码时使用过它,但我仍然更喜欢使我的方法幂等,因此我会从外部传入日期。 - Sean Patrick Floyd

32

我同意Sean Patrick Floyd的观点。

这是我的标准:如果类的方法仅对其接收的参数进行操作,没有外部依赖项(数据库、文件系统、用户配置、其他对象/bean等),则我会使用静态方法,通常在一个具有私有构造函数的最终类中实现。

否则,我会使用Spring bean实现。

因此,在您提出的情况下,根据这个标准,我会编写一个带有静态方法的类。

致敬。


19

将其声明为Spring bean会更好,因为这样它的生命周期就由Spring管理,您最终可以注入依赖项,池化对象,并以适当的方式对其进行测试,更不用说您可以将其用作常规对象并将其作为参数传递,重新定义子类中的方法等等。

简而言之,在大多数情况下,这是更好的设计。然而,在像这样简单的情况下,它并没有太大的区别。


1

在这个评论中的一个好回答 我在Spring单例bean中是否应该使用static

静态变量在一个JVM中只有一个实例。每个Spring上下文中都存在单例。如果你的应用程序只有一个上下文,它们可以完成相同的工作。

但是不要把它们混在一起。在一些旧项目中,我看到一些非纯的实用程序类通过ApplicationContext使用一些Spring bean。这很难为它编写测试用例。


1
虽然这里大多数人支持使用具有静态方法的Util类,而不是Spring bean的想法,但我持相反意见。
1. 依赖注入是有道理的。这是一种工具,用于在不同环境下替换任何Spring Bean的不同实现。最常见的是开发和测试环境之间的差异。但我们将来也可能有新的环境(生产环境、不同的数据传输协议、不同的数据库实现等)。在这种情况下,由Spring注入的接口实现Bean会让生活变得更加轻松。
相反,使用带有静态方法的工具类是众所周知的设计问题,称为紧耦合,并且会导致代码脆弱性。
2. 考虑这样一种情况:你有一个带有静态方法的实用类。在某个时间点,你需要添加一个注入的依赖作为新功能请求。突然间,它不再是一个Util,而是一个UtilBean了。因此,你不得不重命名它并重构调用它的所有代码,而不是向原始Util添加一个方法。重构很便宜,对吗?如果你正在构建一个被其他应用程序使用且你无法控制的库,那就不要这么快下结论。而且,你怎么知道你今天的代码明天不会成为编译库的依赖关系呢?
好的,我们努力工作,将util重命名为bean,一切都很顺利。但是我们收到了一个新的功能请求,接下来我们需要从bean中删除该方法。现在它没有依赖性,我们需要将bean重命名为back util。
如果开发人员使用Spring,他们通常遵循MVC架构设计。在这种情况下,Util类应该放在哪里?听起来像是一个Service,但它似乎是不同的,并且可能有一个单独的包。这不太好。
底线是,在使用Spring时,请使用Beans,不要将Utility类与静态方法混在一起。我认为这个观点对于任何使用依赖注入的应用程序都是有效的。
这是我的文章,关于这个问题:https://medium.com/@pavlomorozov78/static-methods-in-spring-utility-classes-9994ae6aa949

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接