我曾经喜欢充满静态方法的实用程序类。他们对辅助方法进行了很好的整合,否则这些方法会导致冗余和维护困难。它们非常易于使用,无需实例化,无需处置,只需即发即忘。我想这是我第一次无意中尝试创建面向服务的架构 - 许多无状态服务只完成其工作,仅此而已。然而,随着系统的发展,龙就会来临。
多态性
假设我们有一个方法 UtilityClass.SomeMethod 可以愉快地运行。突然我们需要稍微改变一下功能。大多数功能是相同的,但我们仍然必须更改一些部分。如果它不是静态方法,我们可以创建一个派生类并根据需要更改方法内容。因为它是静态方法,所以我们不能。当然,如果我们只需要在旧方法之前或之后添加功能,我们可以创建一个新类并在其中调用旧类 - 但这太恶心了。
接口问题
由于逻辑原因,静态方法不能通过接口定义。由于我们无法重写静态方法,因此当我们需要通过接口传递静态类时,静态类就没用了。这使得我们无法使用静态类作为策略模式的一部分。我们可能会通过以下方式修复一些问题传递委托而不是接口.
Testing
这基本上与上面提到的界面问题密切相关。由于我们交换实现的能力非常有限,因此我们在用测试代码替换生产代码时也会遇到麻烦。同样,我们可以将它们包装起来,但这需要我们更改大部分代码,以便能够接受包装器而不是实际的对象。
促进斑点
由于静态方法通常用作实用方法,而实用方法通常有不同的目的,因此我们很快就会得到一个充满非连贯功能的大类 - 理想情况下,每个类在系统中都应该有一个单一的目的。我宁愿有五倍的课程,只要它们的目的明确。
参数蠕变
首先,那个可爱又无辜的静态方法可能需要一个参数。随着功能的增长,添加了一些新参数。很快就会添加更多可选参数,因此我们创建该方法的重载(或者仅添加默认值,以支持它们的语言)。不久之后,我们就有了一个带有 10 个参数的方法。只有前三个是真正必需的,参数 4-7 是可选的。但是,如果指定了参数 6,则还需要填写 7-9...如果我们创建一个类,其唯一目的是执行此静态方法的操作,我们可以通过在构造函数,并允许用户通过属性或方法设置可选值,以同时设置多个相互依赖的值。另外,如果一个方法已经发展到如此复杂的程度,那么它很可能无论如何都需要位于自己的类中。
要求消费者无缘无故地创建类的实例
最常见的争论之一是,为什么要求我们类的使用者创建一个实例来调用这个单一方法,而之后却不再使用该实例?在大多数语言中创建类的实例是一个非常非常便宜的操作,因此速度不是问题。向消费者添加额外的代码行成本很低,可以为将来更易于维护的解决方案奠定基础。最后,如果您想避免创建实例,只需创建类的单例包装器即可轻松重用 - 尽管这确实要求您的类是无状态的。如果它不是无状态的,您仍然可以创建处理所有内容的静态包装方法,同时从长远来看仍然为您带来所有好处。最后,您还可以创建一个隐藏实例化的类,就好像它是单例一样:MyWrapper.Instance 是一个仅返回 new MyClass() 的属性;
只有西斯才能做到绝对
当然,我不喜欢静态方法也有例外。真正不会带来任何膨胀风险的实用程序类是静态方法的绝佳案例 - 例如 System.Convert。如果您的项目是一次性的,不需要将来维护,那么整体架构实际上并不是很重要 - 静态或非静态并不重要 - 但开发速度很重要。
标准、标准、标准!
使用实例方法并不妨碍您使用静态方法,反之亦然。只要差异化背后有理由,并且是标准化的。没有什么比查看包含不同实现方法的业务层更糟糕的了。