我看到了这个线
想过为什么实用程序类是邪恶的?
可以说我有一个深度类很多的领域模型。我需要能够xml-ify实例。我是否在父对象上创建toXml方法?我是否要创建MyDomainXmlUtility.toXml帮助器类?在这种情况下,业务需求跨越了整个域模型-它真的属于实例方法吗?如果应用程序的xml功能上有一堆辅助方法,那该怎么办?
我看到了这个线
想过为什么实用程序类是邪恶的?
可以说我有一个深度类很多的领域模型。我需要能够xml-ify实例。我是否在父对象上创建toXml方法?我是否要创建MyDomainXmlUtility.toXml帮助器类?在这种情况下,业务需求跨越了整个域模型-它真的属于实例方法吗?如果应用程序的xml功能上有一堆辅助方法,那该怎么办?
Answers:
实用程序类并不是完全邪恶的,但是它们可能违反构成良好的面向对象设计的原理。在一个好的面向对象的设计中,大多数类应该代表一个事物及其所有属性和操作。如果您正在处理某个事物,则该方法可能应该是该事物的成员。
但是,有时您可以使用实用程序类将许多方法组合在一起-例如,java.util.Collections
该类提供了可在任何Java集合上使用的许多实用程序。这些并不是特定于某个特定类型的Collection,而是实现了可在任何Collection上使用的算法。
确实,您需要做的是考虑设计并确定放置方法最有意义的位置。通常,它作为类内部的操作。但是,有时确实是作为实用程序类。但是,当您使用实用程序类时,不要只是将随机方法放入其中,而应根据目的和功能组织这些方法。
我认为,普遍共识是实用程序类本身并不是邪恶的。您只需要谨慎使用它们:
将静态实用程序方法设计为通用且可重用。确保它们是无状态的;即没有静态变量。
如果您有很多实用程序方法,请将它们划分为类,使开发人员可以轻松地找到它们。
不要使用实用程序类,在这些类中,静态或实例方法在域类中会是更好的解决方案。例如,考虑抽象基类或可实例化帮助器类中的方法是否是更好的解决方案。
对于Java 8及更高版本,接口中的“默认方法”可能比实用程序类更好。(例如,请参阅带有默认方法的接口与Java 8中的Abstract类。)
查看此问题的另一种方式是观察到在引用的问题中,“如果实用程序类是“邪恶的””是稻草人的论点。就像我问:
“如果猪可以飞,我应该带雨伞吗?”
在上面的问题,我没有真正说猪都能飞...或者说我用的命题,他们同意可以飞。
典型的“ xyz是邪恶的”陈述是修辞手段,旨在通过摆出极端的观点来使您思考。它们很少(如果有的话)用作文字事实的陈述。
实用程序类存在问题,因为它们无法将职责与支持它们的数据进行分组。
但是,它们非常有用,我一直将它们构建为永久性结构或在更彻底的重构过程中作为垫脚石。
从“ 干净代码”的角度来看,实用程序类违反了“单一职责”和“开放-封闭原则”。他们有很多改变的理由,并且设计上是不可扩展的。它们实际上仅应在重构过程中作为中间组件存在。
class
使用了关键字。它像命名空间一样
x.equals(y)
因为1)事实上,这种状态不应该修改任何状态,这一事实并未得到传达(并且我不能依靠它不知道实现情况)2)我从来没有打算将x
“相比于y
3)我不想考虑“身份” x
或y
仅仅对它们的价值感兴趣。
我想它开始变得邪恶
1)太大(在这种情况下,请将它们分为有意义的类别)。
2)存在不应为静态方法的方法
但是,只要不满足这些条件,我认为它们非常有用。
Widget.compareTo(Widget widget)
与静态WidgetUtils.compare(Widget widgetOne, Widget widgetTwo)
。比较是不应静态完成的示例。
您可以从两个角度看待这个问题:
*Util
方法通常是不良代码设计或惰性命名约定的暗示。util
类/模块。外部库示例假设您正在编写管理贷款和信用卡的应用程序。这些模块中的数据通过Web服务以json
格式公开。从理论上讲,您可以手动将对象转换为in中的字符串json
,但这会重新发明轮子。正确的解决方案是在两个模块中都包含用于将Java对象转换为所需格式的外部库。(在示例图像中,我已经显示了gson)
util
类/模块。在util
不找其他团队成员的情况下撰写自己的作品作为一个用例,假设我们需要在两个应用模块中执行一些计算,但是它们两个都需要知道波兰何时有公共假期。从理论上讲,您可以在模块内部进行这些计算,但是最好将此功能提取到单独的模块中。
这里很小,但是很重要。您编写的类/模块不是HolidayUtil
,而是PolishHolidayCalculator
。从功能上讲,它是一util
类,但我们设法避免使用通用词。
现在回头看这个问题,我想说C#扩展方法完全破坏了对实用程序类的需求。但是,并非所有语言都具有如此精巧的构造。
您还可以使用JavaScript,在其中只需向现有对象添加新功能即可。
但是我不确定是否真的有一种优雅的方法可以用像C ++这样的旧语言来解决这个问题...
好的OO代码有点很难编写,而且很难找到,因为编写好OO代码比编写体面的功能代码需要更多的时间/知识。
而且当您预算有限时,您的老板并不总是很高兴看到您花了一整天写了一堆课...
我并不完全同意实用程序类是邪恶的。
尽管实用程序类可能会在某些方面违反OO主体,但它们并不总是不好的。
例如,假设您需要一个函数,该函数将清除所有与value匹配的子字符串的字符串x
。
stl c ++(截至目前)不直接支持此功能。
您可以创建的多态扩展std::string
。
但是问题是,您是否真的希望项目中使用的每个字符串都成为扩展字符串类?
有时候,OO并没有真正意义,这就是其中之一。我们希望我们的程序与其他程序兼容,因此我们将坚持std::string
并创建一个类StringUtil_
(或其他类)。
我要说的是,如果您每堂课只使用一个工具,那是最好的。我想说对所有类都使用一个实用程序或对一个类使用多个实用程序是很愚蠢的。
大多数Util类很糟糕,因为:
静态库和动态库有一些类比。
当我无法向类中添加方法(例如,Account
被Jr. Developers禁止更改)时,我仅向Utilities类中添加了一些静态方法,如下所示:
public static int method01_Account(Object o, String... args) {
Account acc = (Account)o;
...
return acc.getInt();
}
Account
文件。或者,最好使用非锁定源控制系统。
Account
文件已被锁定,因此开发人员无法对其进行更改。作为一名小型开发人员,要解决这个问题,他的做法如上所述。也就是说,最好只是获得对该文件的写访问权并正确执行它。