代码之家  ›  专栏  ›  技术社区  ›  hvgotcodes

效用类是邪恶的?[关闭]

  •  79
  • hvgotcodes  · 技术社区  · 14 年前

    我看到了这根线

    If a "Utilities" class is evil, where do I put my generic code?

    想想为什么效用类是邪恶的?

    假设我有一个领域模型,它有几十个类。我需要能够XML化实例。我要对父母做toxml方法吗?我是否创建myDomainXmlUtility.ToXML帮助程序类?在这种情况下,业务需要跨越整个域模型——它真的属于实例方法吗?如果应用程序的XML功能上有许多辅助方法,那该怎么办?

    14 回复  |  直到 5 年前
        1
  •  104
  •   MC Emperor    6 年前

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

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

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

        2
  •  47
  •   Stephen C    7 年前

    我认为普遍的共识是效用类不是邪恶的 本身 . 你只需要明智地使用它们:

    • 将静态实用程序方法设计为通用的和可重用的。确保它们是无状态的,即没有静态变量。

    • 如果你有很多实用方法,把它们划分成类,这样开发者就可以很容易地找到它们。

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

    • 对于Java 8而言,接口中的“默认方法”可能是比实用工具类更好的选择。


    另一种看待这个问题的方法是观察在引用的问题中, 如果实用程序类是“邪恶的” 是一个strawman参数。就像我问的:

    “如果猪能飞,我应该带伞吗?”.

    在上面的问题中,我并不是说猪能飞…或者我同意他们 能够 飞。

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

        3
  •  12
  •   Alain O'Dea    9 年前

    实用程序类是有问题的,因为它们无法用支持它们的数据对职责进行分组。

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

    从A Clean Code 透视实用程序类违反了单一责任和开放-关闭原则。它们有很多改变的原因,并且设计上是不可扩展的。它们实际上只应该作为中间代码在重构期间存在。

        4
  •  7
  •   Enno Shioji    10 年前

    我想当

    1) 它变得太大了 (在本例中,只需将它们分组为有意义的类别)。
    2) 存在不应是静态方法的方法

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

        5
  •  4
  •   Marcin Szymczak    7 年前

    经验法则

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

    • 总的来说, *util->methods通常是坏代码设计或懒惰命名约定的建议。
    • 它是可重用跨域无状态功能的合法设计解决方案。请注意,几乎所有常见问题都有现有的解决方案。

    例1。正确使用 util classes/modules。外部库示例

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


    例2。正确使用 util classes/modules。编写自己的 util without exceptions to other team members

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

    这里有一些小但重要的细节。您编写的类/模块不是调用 holidayUtil ,而是调用 polishholidayCalculator 。从功能上讲,它是一个 util class,但我们已经设法避免使用通用词。

    广告代码设计或懒惰的命名约定。
  • 它是可重用跨域无状态功能的合法设计解决方案。请注意,几乎所有常见问题都有现有的解决方案。

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

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

    enter image description here


    例2。正确使用 乌蒂尔 类/模块。写你自己的 乌蒂尔 不给其他团队成员找借口

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

    这里有一些小但重要的细节。未调用您编写的类/模块 HolidayUtil 但是 PolishHolidayCalculator . 在功能上,它是 乌蒂尔 类,但我们已设法避免使用泛型单词。

    enter image description here

        6
  •  3
  •   Larry Watanabe    14 年前

    实用程序类是坏的,因为它们意味着你太懒了,无法为类想出更好的名称:)

    正因为如此,我才懒惰。有时候你只需要把工作做完,你的脑子一片空白。这就是“实用程序”类开始出现的时候。

        7
  •  3
  •   HumbleWebDev    7 年前

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

    您还可以使用javascript,只需向现有对象添加一个新的函数即可。

    但我不确定是否真的有一种优雅的方式来解决这个问题在一个更古老的语言,如C++…

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

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

        8
  •  3
  •   b2f133c6-1534-4f13-824c-b5c0de Glen Best    5 年前

    我并不完全同意效用类是邪恶的。

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

    例如,假设您想要一个函数,它将清除所有匹配值的子字符串 x .

    STL C++(现在)不能直接支持这一点。

    你可以创建一个 std::string .

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

    有时OO真的没有意义,这就是其中之一。我们希望我们的程序与其他程序兼容,因此我们将坚持 STD::字符串 创建一个类 StringUtil_ (或某物)。

    我想说,最好每堂课坚持一次。我想说,为所有类使用一个实用程序,或者为一个类使用多个实用程序是很愚蠢的。

        9
  •  2
  •   mdma    14 年前

    仅仅因为设计师想不出一个合适的地方来放置代码,就很容易给某个实用程序打上商标。通常很少有真正的“实用程序”。

    作为经验法则,我通常将代码保存在第一次使用它的包中,然后只有在稍后发现它确实在其他地方需要时才重构到更通用的地方。唯一的例外是,如果我已经有了一个执行类似/相关功能的包,并且代码最适合这个包。

        10
  •  2
  •   seand    14 年前

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

        11
  •  1
  •   Marc T    8 年前

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

        12
  •  1
  •   Sridhar Sarnobat    5 年前

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

    1. 它们扩大了方法的范围。 它们将代码公开,否则将是私有的。如果不同类中的多个调用方需要Util方法,并且该方法是稳定的(即不需要更新),那么我认为最好将私有助手方法复制并粘贴到调用类中。一旦将其公开为API,就很难理解JAR组件的公共入口点是什么(您维护一个树结构的层次结构,每个方法有一个父级)。这更容易在精神上分离成组件,而当您有从多个父方法调用的方法时,组件就更难分离了)。
    2. 它们会导致死代码。 随着时间的推移,随着应用程序的发展,Util方法将不再使用,最终会导致未使用的代码污染代码库。如果它仍然是私有的,编译器会告诉你这个方法没有使用过,你可以删除它(最好的代码是完全没有代码)。一旦您将这种方法设为非私有,您的计算机将无法帮助您删除未使用的代码。它可以从一个不同的JAR文件中调用,这是所有计算机都知道的。

    静态库和动态库有一些类似之处。

        13
  •  0
  •   Sid J    6 年前

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

        14
  •  -1
  •   Mr. White    14 年前

    当我无法向类中添加方法时(例如, Account 被Jr.开发人员锁定以防更改),我只是向我的实用程序类添加了一些静态方法,如下所示:

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