说我有一个旨在执行单个功能的类。执行该功能后,可以将其销毁。是否有任何理由偏爱其中一种方法?
// Initialize arguments in constructor MyClass myObject = new MyClass(arg1, arg2, arg3); myObject.myMethod(); // Pass arguments to method MyClass myObject = new MyClass(); myObject.myMethod(arg1, arg2, arg3); // Pass arguments to static method MyClass.myMethod(arg1, arg2, arg3);
我故意对细节含糊不清,以尝试获取针对不同情况的指导。但是我真的没有想到像Math.random()这样的简单库函数。我在想更多的类来执行一些特定的,复杂的任务,但是只需要一个(公共)方法即可。
我曾经喜欢用静态方法填充的实用程序类。他们对辅助方法进行了很好的合并,否则将导致冗余和维护麻烦。它们非常易于使用,无需实例化,无需处理,只是忘了忘了。我想这是我第一次尝试创建面向服务的体系结构- 许多无状态服务只是完成了工作,而没有其他。但是,随着系统的发展,巨龙将会来临。
多态性 假设我们有方法UtilityClass.SomeMethod可以愉快地嗡嗡作响。突然,我们需要稍微更改功能。大多数功能是相同的,但是我们仍然必须更改几个部分。如果不是静态方法,我们可以制作一个派生类并根据需要更改方法的内容。由于它是静态方法,因此不能。当然,如果我们只需要在旧方法之前或之后添加功能,则可以创建一个新类并在其中调用旧类- 但这很麻烦。
接口问题 由于逻辑原因,无法通过接口定义静态方法。而且由于无法覆盖静态方法,因此当需要通过它们的接口传递静态类时,静态类是无用的。这使我们无法将静态类用作策略模式的一部分。我们可以通过传递委托而不是接口来修补一些问题。
测试 这基本上与上面提到的界面问题息息相关。由于我们交换实现的能力非常有限,因此我们也很难用测试代码替换生产代码。同样,我们可以将它们包装起来,但是它要求我们更改代码的大部分内容,以便能够接受包装器而不是实际的对象。
福斯特斑点 为静态方法通常被用作实用方法和实用方法通常都会有不同的目的,我们将很快结束了充满了非相干功能的一大类- 理想情况下,每个类应该有系统内一个单一的目的。只要他们的目的得到明确定义,我宁愿选择五倍的课程。
参数蠕变 首先,这个可爱又天真的静态方法可能只需要一个参数。随着功能的增长,添加了两个新参数。不久便添加了可选的其他参数,因此我们创建了该方法的重载(或仅添加默认值(使用支持它们的语言))。不久,我们有了一个采用10个参数的方法。实际上只需要前三个,参数4-7是可选的。但是,如果指定了参数6,则还必须填写7-9 …如果我们仅出于执行此静态方法的目的而创建了一个类,则可以通过在构造函数,并允许用户通过属性或方法设置可选值,以同时设置多个相互依赖的值。另外,如果一种方法已经发展到如此复杂的程度,
要求消费者无缘无故地创建类的实例 最常见的论点之一是,为什么要求我们的类的使用者创建一个实例来调用该单一方法,而之后却不再使用该实例呢?在大多数语言中,创建类的实例是非常便宜的操作,因此速度不是问题。向消费者添加额外的代码行是为将来奠定更易于维护的解决方案奠定基础的低成本。最后,如果要避免创建实例,只需创建类的单例包装即可,以方便重用- 尽管这确实要求类是无状态的。如果不是无状态的,您仍然可以创建处理所有内容的静态包装器方法,而从长远来看仍然可以为您带来所有好处。最后,
只有Sith可以处理绝对值 当然,我不喜欢静态方法也有例外。真正的实用程序类不会造成任何膨胀的风险,对于静态方法来说就是个很好的例子- 以System.Convert为例。如果您的项目是一次性的,对将来的维护没有要求,那么总体架构真的不是很重要-静态还是非静态,都没关系- 但是开发速度确实如此。
标准,标准,标准! 使用实例方法并不妨碍您也使用静态方法,反之亦然。只要差异化背后有其合理性并被标准化即可。没有什么比查看遍布着不同实现方法的业务层更糟糕的了。