我看到了这个帖子
If a "Utilities" class is evil, where do I put my generic code?
并且想到为什么实用类邪恶?
可以说我有一个很多类的域模型。我需要能够xml-ify实例。我是否在父级上创建了一个toXml方法?我是否制作了MyDomainXmlUtility.toXml助手类?这是业务需求跨越整个域模型的情况 - 它真的属于实例方法吗?如果应用程序的xml功能上有一堆辅助方法怎么办?
实用类并不完全是邪恶的,但它们可能违反构成良好的面向对象设计的原则。在良好的面向对象设计中,大多数类应该代表单个事物及其所有属性和操作。如果你正在操作某个东西,那么该方法应该是该东西的成员。
但是,有时您可以使用实用程序类将多个方法组合在一起 - 例如java.util.Collections
类,它提供了许多可以在任何Java Collection上使用的实用程序。这些并非特定于一种特定类型的Collection,而是实现可在任何Collection上使用的算法。
实际上,您需要做的是考虑您的设计并确定最适合放置方法的位置。通常,它是一个类内的操作。但是,有时,它确实是一个实用类。但是,当您使用实用程序类时,不要只是将随机方法放入其中,而是按用途和功能组织方法。
包含无状态静态方法的实用程序类可能很有用。这些通常很容易进行单元测试。
使用Java 8,您可以在接口中使用静态方法...问题已解决。
大多数Util类都很糟糕,因为:
静态与动态库有一些类比。
公用事业类并不总是邪恶的。但是它们应该只包含各种功能中常见的方法。如果存在仅在有限数量的类中可用的方法,请考虑将抽象类创建为公共父类并将方法放入其中。
当我无法向类添加方法时(比如,qzxswpoi被Jr. Developers的更改锁定),我只是向我的Utilities类添加一些静态方法,如下所示:
Account
我认为普遍的共识是效用类本身并不是邪恶的。你只需要明智地使用它们:
另一种看待这个问题的方法是观察在引用的问题中,“如果效用类是”邪恶的“,那么就是一个稻草人的论点。它像我一样问:
“如果猪可以飞,我应该带伞吗?”
在上面的问题中,我实际上并不是说猪可以飞......或者我同意他们可以飞的命题。
典型的“xyz是邪恶的”陈述是修辞手段,旨在通过提出一个极端的观点让你思考。他们很少(如果有的话)打算作为字面事实的陈述。
实用程序类是有问题的,因为它们无法将责任与支持它们的数据分组。
然而,它们非常有用,我将它们作为永久性结构或在更彻底的重构过程中作为垫脚石一直构建。
从Clean Code的角度来看,实用类违反了单一责任和开放封闭原则。他们有很多改变的理由,而且设计不可扩展。它们实际上应该只在重构期间作为中间残骸存在。
我想它开始变得邪恶了
1)它太大了(在这种情况下只将它们分成有意义的类别)。 2)存在不应该是静态方法的方法
但只要不满足这些条件,我认为它们非常有用。
您可以从两个角度来看待这个问题:
*Util
方法通常是错误的代码设计或惰性命名约定的建议。util
类/模块。外部库示例我们假设您正在编写管理贷款和信用卡的应用程序。来自这些模块的数据通过json
格式的Web服务公开。从理论上讲,您可以手动将对象转换为将在json
中的字符串,但这会重新发明轮子。正确的解决方案是在两个模块中包含用于将java对象转换为所需格式的外部库。 (在示例图像中我显示了gson)
util
类/模块。写下你自己的util
,没有任何借口给其他团队成员作为一个用例假设我们需要在两个应用模块中执行一些计算,但他们都需要知道波兰何时有公共假期。从理论上讲,您可以在模块内部进行这些计算,但最好将此功能提取到单独的模块中。
这是一个小而重要的细节。你写的类/模块不叫HolidayUtil
,而是PolishHolidayCalculator
。在功能上它是一个util
类,但我们设法避免泛型词。
实用程序类很糟糕,因为它们意味着你懒得想出一个更好的名字:)
话虽这么说,我很懒。有时候你只需要完成工作而你的思想是空白的......那就是“实用工具”课程开始悄悄进入的时候。
现在回顾这个问题,我会说C#扩展方法完全破坏了对实用程序类的需求。但并非所有语言都有这样的天才构造。
您还可以使用JavaScript,只需向现有对象添加新功能即可。
但是我不确定在像C ++这样的旧语言中是否真的有一种优雅的方法来解决这个问题......
良好的OO代码有点难以编写,并且很难找到,因为编写Good OO需要比编写体面的功能代码更多的时间/知识。
当你的预算有限时,你的老板总是很高兴看到你花了一整天的时间写一堆课......
我并不完全同意实用类是邪恶的。
虽然实用程序类可能在某些方面违反OO主体,但它们并不总是坏的。
例如,假设您需要一个函数来清理与值x
匹配的所有子字符串的字符串。
stl c ++(截至目前)并不直接支持这一点。
您可以创建std::string
的多态扩展。
但问题是,你真的希望你在项目中使用的每个字符串都是你的扩展字符串类吗?
有时OO没有意义,这就是其中之一。我们希望我们的程序与其他程序兼容,因此我们将坚持使用std::string
并创建一个类StringUtil_
(或其他东西)。
如果你坚持每班一个工具,我会说最好。我会说,为所有类创建一个util或者为一个类创建多个util是很愚蠢的。
仅仅因为设计师无法想到放置代码的合适位置,所以很容易将某个实用程序称为实用程序。通常很少有真正的“实用工具”。
根据经验,我通常会将代码保存在首次使用它的包中,然后如果我发现稍后在其他地方确实需要它,那么只能重构到更通用的地方。唯一的例外是如果我已经有一个执行类似/相关功能的包,并且代码最适合那里。