Java 中静态 Util 类和方法的替代方法

hat*_*lla 5 java oop

说,我想要这个方法,它接受一个 Set 并根据某些逻辑将其设置为一个字符串的格式。例如。

public String formatCustomerSet(final Set<Customer> customers) {
    String result = "";
    for (Customer customer : customers) {
        result += customer.getFirstName() + " : " + customer.getLastName() + "\n";
    }

    return result;
}
Run Code Online (Sandbox Code Playgroud)

我在几个类中使用此代码。现在,我应该把这个放在哪里?我发现应该避免使用实用程序类而不应该使用它? https://lostechies.com/chrismissal/2009/06/01/anti-patterns-and-worst-practices-utils-class/

那么,它应该是像 CustomerFormatter 这样使用的特定名称的 Util 类,还是我们应该从中创建一个 OOP 类?推荐哪一个,为什么?

ImJ*_*Lol 5

我不同意应该避免 util 类这一事实。拥有一个包含纯粹实用程序的静态方法的类是完全可以的。有时函数或操作应该只是函数或操作。并不总是需要将它们与某些抽象对象类型或其他类型相关联。

然而,我确实同意的是,在创建 util 类时,应该严格定义该类将提供哪些类型的实用程序。如果您有一堆与执行数学运算相关的静态方法,您可以创建一个 util 类ExtendedMath。如果你做了很多数学课并且课程变得太丰富,请尝试进一步细化它。按数学类型对它们进行分组,例如AlgebraVector

最后,它主要只是试图运用常识。函数成为对象的一部分是否有意义,或者它可以只是任意操作?

在您的情况下,您必须问自己一个问题:“我想创建我的代码对实现的硬依赖吗formatCustomerSet?”。如果您 100% 确定您将始终以完全相同的方式格式化客户集,并且您永远不会需要不同的格式化程序,那么使用静态方法可能没问题。如果没有,那么也许最好将其CustomerSetFormatter作为非静态函数放在类中。

我无法给你是或否的答案,因为你必须自己权衡利弊。只需考虑以下事项:

  • 当您引用静态方法时,您正在创建对该静态方法的硬依赖。有时这是可以的,有时则不然。软件开发的一个核心原则是重用。您是否也可以在其他上下文中重用调用静态函数的代码?或者静态函数是否过于特定于上下文?
  • 编程的另一个核心原则是依赖注入。假设您Class A需要客户格式化程序。你能做的就是你可以做一个interface CustomerFormatter. 然后Class A定义一个构造函数:A(CustomerFormatter formatter)Class A这允许您在使用不同的实现时重用 CustomerFormatter。这大大提高了Class A. 当使用静态函数时,这不再可能。
  • Math常见的泛型操作(例如、min()max()ceil()中定义的函数floor())完全可以保证是静态函数。他们做一件常用的事情,而且只做一件事情。一般来说,您可以将这样的函数作为静态方法完全有必要的示例。
  • 你的函数是纯函数吗?对于任何唯一的输入,该函数始终给出完全相同的输出。如果输入保持不变,对相同函数的后续调用将始终产生相同的结果。如果是这种情况,那么将您的方法设为静态就可以了。如果情况并非如此,并且对同一函数的后续调用根据某些任意状态或之前完成的调用给出不同的输出,那么您应该考虑将其设置为非静态。创建为相同输入提供不同输出的静态函数,因为它们依赖于某种状态,通常被视为反模式

我希望这对你有一点帮助。


jro*_*ook 1

使用Java流,你实际上可以通过以下一行得到你想要的东西(假设toString()类中有一个好的Customer):

String result = 
    customers.stream().map(Customer::toString).collect(Collectors.joining("\n"));
Run Code Online (Sandbox Code Playgroud)

放置它的一个好地方可能是班级Customer本身。但我会开始使用它,只有在收集了有关用例的一些信息后,我才会考虑将其重构为一个独立的类。

编辑(评论的答案):是的,我首先将其设为Customer类中的静态方法,因为它实际上不使用该类中的任何字段。

编辑2(注):顺便说一句,如果您想在问题中使用该方法,请考虑使用 aStringBuilder而不是String.