实用程序类是邪恶的吗?

发布于 2024-09-11 16:33:41 字数 1431 浏览 8 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

羅雙樹 2024-09-18 16:33:41

实用程序类并不完全是邪恶的,但它们可能违反构成良好的面向对象设计的原则。在良好的面向对象设计中,大多数类应该表示单个事物及其所有属性和操作。如果您正在操作一个事物,那么该方法可能应该是该事物的成员。

但是,有时您可以使用实用程序类将许多方法组合在一起 - 例如 java.util.Collections 类,它提供了许多可在任何 Java Collection 上使用的实用程序。这些并不特定于一种特定类型的集合,而是实现可用于任何集合的算法。

实际上,您需要做的是考虑您的设计并确定将方法放在最有意义的位置。通常,它是类内部的操作。然而,有时,它确实是作为一个实用程序类。但是,当您确实使用实用程序类时,不要只是向其中添加随机方法,而是按用途和功能组织方法。

Utility classes aren't exactly evil, but they can violate the principles that compose a good object-oriented design. In a good object-oriented design, most classes should represent a single thing and all of its attributes and operations. If you are operating on a thing, that method should probably be a member of that thing.

However, there are times when you can use utility classes to group a number of methods together — an example being the java.util.Collections class which provides a number of utilities that can be used on any Java Collection. These aren't specific to one particular type of Collection, but instead implement algorithms that can be used on any Collection.

Really, what you need to do is think about your design and determine where it makes the most sense to put the methods. Usually, it's as operations inside of a class. However, sometimes, it is indeed as a utility class. When you do use a utility class, however, don't just throw random methods into it, instead, organize the methods by purpose and functionality.

以酷 2024-09-18 16:33:41

我认为普遍的共识是实用程序类本身并不是邪恶的。您只需要明智地使用它们:

  • 将静态实用程序方法设计为通用且可重用。确保他们是无国籍的;即没有静态变量。

  • 如果您有很多实用方法,请将它们划分为类,以便开发人员轻松找到它们。

  • 不要使用实用程序类,因为域类中的静态或实例方法是更好的解决方案。例如,考虑抽象基类或可实例化帮助器类中的方法是否是更好的解决方案。

  • 对于 Java 8 及以上版本,接口中的“默认方法”可能是比实用程序类更好的选择。 (请参阅 何时使用:Java 8+ 接口默认方法,与抽象方法例如。)


看待这个问题的另一种方式是观察在引用的问题中,“如果实用程序类是“邪恶的””是一个稻草人论点。就像我在问:

“如果猪会飞,我应该带伞吗?”。

在上面的问题中,我实际上并不是说猪可以飞……或者我同意它们可以1的命题。

典型的“xyz 是邪恶的”陈述是修辞手段,旨在通过提出极端观点来让你思考。它们很少(如果有的话)作为字面事实的陈述。


1 - 您不应该将这个稻草人问题解释为关于您在户外时是否应该始终随身携带雨伞的建议

I think that the general consensus is that utility classes are not evil per se. You just need to use them judiciously:

  • Design the static utility methods to be general and reusable. Make sure that they are stateless; i.e. no static variables.

  • If you have lots of utility methods, partition them into classes in a way that will make it easy for developers to find them.

  • Don't use utility classes where static or instance methods in a domain class would be a better solution. For example, consider if methods in an abstract base class or an instantiable helper class would be a better solution.

  • For Java 8 onwards, "default methods" in an interface may be a better option than utility classes. (See When to use: Java 8+ interface default method, vs. abstract method for example.)


The other way to look at this Question is to observe that in the quoted Question, "If utility classes are "evil"" is a strawman argument. Its like me asking:

"If pigs can fly, should I carry an umbrella?".

In the above question I am not actually saying that pigs can fly ... or that I agree with the proposition that they could fly1.

Typical "xyz is evil" statements are rhetorical devices that are intended to make you think by posing an extreme viewpoint. They are rarely (if ever) intended as statements of literal fact.


1 - And you should NOT interpret that strawman question as advice on whether you should always take an umbrella with you when you are outdoors.

廻憶裏菂餘溫 2024-09-18 16:33:41

实用程序类存在问题,因为它们无法将职责与支持它们的数据分组。

然而,它们非常有用,我一直将它们构建为永久结构或在更彻底的重构过程中作为垫脚石。

干净代码的角度来看,实用程序类违反了单一职责和开闭原则。它们有很多改变的理由,并且在设计上是不可扩展的。它们确实应该只在重构过程中作为中间残骸存在。

Utility classes are problematic because they fail to group responsibilities with the data that supports them.

They are however extremely useful and I build them all the time as either permanent structures or as stepping stones during a more thorough refactor.

From a Clean Code perspective utility classes violate the Single Responsibility and the Open-Closed Principle. They have lots of reasons to change and are by design not extensible. They really should only exist during refactoring as intermediate cruft.

故事未完 2024-09-18 16:33:41

我想它开始变得邪恶,当

1)它变得太大(在这种情况下只需将它们分组到有意义的类别)。
2)存在不应该是静态方法的方法

但是只要不满足这些条件,我认为它们非常有用。

I suppose it starts to become evil when

1) It gets too big (just group them into meaningful categories in this case).
2) Methods that should not be static methods are present

But as long as these conditions are not met, I think they are very useful.

随梦而飞# 2024-09-18 16:33:41

经验法则

您可以从两个角度来看待这个问题:

  • 总体而言 *Util 方法通常暗示着糟糕的代码设计或惰性命名约定。
  • 它是可重用的跨域无状态功能的合法设计解决方案。请注意,几乎所有常见问题都有现有的解决方案。

示例 1. util 类/模块的正确使用。外部库示例

假设您正在编写管理贷款和信用卡的应用程序。这些模块中的数据通过 Web 服务以 json 格式公开。
理论上,您可以手动将对象转换为 json 中的字符串,但这会重新发明轮子。正确的解决方案是在两个模块中都包含用于将 java 对象转换为所需格式的外部库。 (在示例图片中,我显示了 gson

在此处输入图像描述


示例 2. 正确使用 <代码>util 类/模块。编写自己的 util 而不给其他团队成员找借口

作为一个用例,假设我们需要在应用程序的两个模块中执行一些计算,但两个模块都需要知道波兰何时有公共假期。理论上,您可以在模块内进行这些计算,但最好将此功能提取到单独的模块中。

这是一个很小但很重要的细节。您编写的类/模块不称为 HolidayUtil,而是 PolishHolidayCalculator。从功能上讲,它是一个 util 类,但我们设法避免使用通用词。

输入图像描述这里

Rule of thumb

You can look at this problem from two perspectives:

  • Overall *Util methods are often a suggestion of bad code design or lazy naming convention.
  • It is legitimate design solution for reusable cross-domain stateless functionalities. Please note that for almost all common problems there are existing solutions.

Example 1. Correct usage of util classes/modules. External library example

Let's assume you are writing application which manages loans and credit cards. Data from these modules is exposed through web services in json format.
In theory you can manually convert objects to strings which will be in json, but that would reinvent the wheel. Correct solution would be to include in both modules external library used to convert java objects to desired format. (in example image I have shown gson)

enter image description here


Example 2. Correct usage of util classes/modules. Writing your own util without excuses to other team members

As a use case assume that we need to perform some calculations in two modules of application, but both of them need to know when there are public holidays in Poland. In theory you can make these calculations inside modules, but it would be better to extract this functionality to separate module.

Here is small, but important detail. Class/module you have written is not called HolidayUtil, but PolishHolidayCalculator. Functionally it is a util class, but we have managed to avoid generic word.

enter image description here

℡Ms空城旧梦 2024-09-18 16:33:41

实用程序类很糟糕,因为它们意味着您懒得为该类想出更好的名称:)

话虽如此,我很懒。有时你只需要完成工作,但你的大脑一片空白……这就是“实用”课程开始悄然出现的时候。

Utility classes are bad because they mean you were too lazy to think up a better name for the class :)

That being said, I am lazy. Sometimes you just need to get the job done and your mind's a blank .. that's when "Utility" classes start creeping in.

烈酒灼喉 2024-09-18 16:33:41

我不完全同意实用程序类是邪恶的。

虽然实用程序类可能在某些方面违反了面向对象原则,但它们并不总是不好的。

例如,假设您需要一个函数来清理字符串中与值 x 匹配的所有子字符串。

STL C++(到目前为止)并不直接支持这一点。

您可以创建 std::string 的多态扩展。

但问题是,您真的希望项目中使用的每个字符串都是扩展字符串类吗?

有时,面向对象并没有真正的意义,这就是其中之一。我们希望我们的程序与其他程序兼容,因此我们将坚持使用 std::string 并创建一个类 StringUtil_ (或其他东西)。

我想说,最好每个类坚持使用一个 util。我想说,为所有类使用一个 utils 或为一个类使用多个 utils 是愚蠢的。

I don't entirely agree that utility classes are evil.

While a utility class may violate OO principles in some ways, they aren't always bad.

For example, imagine you want a function that will clean a string of all substrings matching the value x.

STL C++ (as of now) doesn't directly support this.

You could create a polymorphic extension of std::string.

But the problem is, do you really want EVERY string you use in your project to be your extended string class?

There are times when OO doesn't really make sense, and this is one of them. We want our program to be compatible with other programs, so we will stick with std::string and create a class StringUtil_ (or something).

I'd say it's best if you stick with one util per class. I'd say it's silly to have one util for all classes or many utils for one class.

烟花易冷人易散 2024-09-18 16:33:41

现在回顾这个问题,我想说 C# 扩展方法完全消除了对实用程序类的需求。但并非所有语言都具有如此天才的构造。

您还可以使用 JavaScript,在其中可以直接向现有对象添加新函数。

但我不确定是否真的有一种优雅的方法可以用像 C++ 这样的旧语言来解决这个问题...

好的 OO 代码有点难以编写,并且很难找到,因为编写好的 OO 需要更多的时间/知识而不是编写像样的功能代码。

当你的预算有限时,你的老板并不总是很高兴看到你花了一整天的时间编写一堆课程......

Looking back at this question now, I'd say that C# extension methods completely destroy the need for utility classes. But not all languages have such an in-genius construct.

You also have JavaScript, where you can just add a new function right to the existing object.

But I'm not sure there really is an elegant way to solve this problem in an older language like C++...

Good OO code is kinda hard to write, and is hard to find since writing Good OO requires a lot more time/knowledge than writing decent functional code.

And when you're on a budget, your boss isn't always happy to see you've spent the whole day writing a bunch of classes...

小忆控 2024-09-18 16:33:41

仅仅因为设计者想不出放置代码的合适位置,就很容易将某些东西标记为实用程序。真正的“实用工具”往往很少。

根据经验,我通常将代码保留在首次使用的包中,然后仅在发现以后其他地方确实需要它时才重构到更通用的位置。唯一的例外是,如果我已经有一个执行类似/相关功能的包,并且代码最适合那里。

It's very easy to brand something a utility simply because the designer couldn't think of an appropriate place to put the code. There are often few true "utilities".

As a rule of thumb, I usually keep code in the package where it is first used, and then only refactor to a more generic place if I find that later it really is needed elsewhere. The only exception is if I already have a package that performs similar/related functionality, and the code best fits there.

遗忘曾经 2024-09-18 16:33:41

包含无状态静态方法的实用程序类可能很有用。这些通常很容易进行单元测试。

Utility classes containing stateless static methods can be useful. These are often very easy to unit test.

吃素的狼 2024-09-18 16:33:41

大多数 Util 类都是不好的,因为:

  1. 它们扩大了方法的范围。它们将本来是私有的代码公开。如果 util 方法被不同类中的多个调用者需要并且稳定(即不需要更新),我认为最好将私有帮助器方法复制并粘贴到调用类中。一旦你将它公开为 API,你就会更难理解 jar 组件的公共入口点是什么(你维护一个树形结构,称为层次结构,每个方法都有一个父级。这更容易在心理上隔离成组件,而在以下情况下会更难)您有从多个父方法调用的方法)。
  2. 它们会导致死代码。 随着应用程序的发展,Util 方法会随着时间的推移而变得不被使用,最终会导致未使用的代码污染您的代码库。如果它保持私有,您的编译器会告诉您该方法未使用,您可以将其删除(最好的代码是根本没有代码)。一旦您将此类方法设为非私有,您的计算机将无法帮助您删除未使用的代码。对于所有计算机来说,它可能是从不同的 jar 文件调用的。

静态库与动态库有一些类比。

Most Util classes are bad because:

  1. They broaden the scope of methods. They make code public that would otherwise be private. If the util method is needed by multiple callers in separate classes and is stable (i.e. doesn't need updating) it's better in my opinion to copy and paste private helper methods into the calling class. Once you expose it as an API, you make it harder to understand what the public entry point to a jar component is (you maintain a tree structured called hierarchy with one parent per method. This is easier to mentally segregate into components which is harder when you have methods called from multiple parent methods).
  2. They result in dead code. Util methods over time become unused as your app evolves and you end up with unused code polluting your code base. If it had remained private your compiler would tell you the method is unused and you could just remove it (the best code is no code at all). Once you make such a method non private your computer will be powerless to help you remove unused code. It may be called from a different jar file for all the computer knows.

There are some analogies to static vs dynamic libraries.

尝蛊 2024-09-18 16:33:41

使用 Java 8,您可以在接口中使用静态方法...问题解决了。

With Java 8 you can use static methods in interfaces ... problem solved.

你丑哭了我 2024-09-18 16:33:41

当我无法向类添加方法时(例如,Account 被锁定以防止 Jr. Developers 进行更改),我只需向 Utilities 类添加一些静态方法,如下所示:

public static int method01_Account(Object o, String... args) {
    Account acc = (Account)o;
    ...
    return acc.getInt();
}  

When I can't add a method to a class (say, Account is locked against changes by Jr. Developers), I just add a few static methods to my Utilities class like so:

public static int method01_Account(Object o, String... args) {
    Account acc = (Account)o;
    ...
    return acc.getInt();
}  
傲世九天 2024-09-18 16:33:41

实用程序类并不总是邪恶的。但它们应该只包含广泛功能中通用的方法。如果某些方法只能在有限数量的类中使用,请考虑创建一个抽象类作为公共父类并将这些方法放入其中。

Utility classes are not always evil. But they should only contain the methods that are common across a wide range of functionality. If there are methods that are only usable among a limited number of classes, consider creating a abstract class as a common parent and put the methods in it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文