实用程序类:静态类与成员变量与局部变量

本文关键字:成员 局部变量 变量 静态类 实用程序 | 更新日期: 2023-09-27 18:25:04

我正在创建一个实用程序类CommonDaoOperations,它包含几个通用方法:CreateUpdateDelete。这不是基类,因为有些DAO更复杂,不能使用这些泛型方法,但许多DAO可以。

我现在正在思考实用程序类应该是什么样子的:

  • 仅具有静态泛型方法的静态类
  • 具有泛型方法的常规类,每个DAO作为私有只读成员创建一次
  • 具有泛型方法的常规类,每个DAO方法创建一次(在每次调用中)

为每个DAO/方法创建一个类的实例显然比调用静态方法成本更高,但我敢肯定,在几乎任何应用程序中,这些成本都是可以忽略的。

我更喜欢解决方案2或3,因为非静态类的好处(接口,可以模拟,可以派生/增强,如果必要的话,可以在未来通过构造函数收集参数(与静态类中的10参数方法相比))。

所以我想真正的问题是:我应该把我的实用程序类创建为成员变量,还是按照DAO方法实例化它?

public void Create(User user) { 
   new CommonDaoOperations().Create(user);
}
public void Delete(User user) {
   var daoOps = new CommonDaoOperations();
   daoOps.CheckSomething(); // just an example of multiple calls to the class
   daoOps.Delete(user);
}

我很想听听其他开发者对这些方法的看法,或者是否还有更好的方法。

编辑

我刚刚意识到,我应该更多地考虑方法#3——正如Vadim所指出的,当具体类在每个方法中实例化时,替换它会很麻烦,但我可以在属性中考虑这一点:

private CommonDaoOperations DaoOps {
    get { return new CommonDaoOperations(); }
}
public void Create(User user) {
   DaoOps.Create(user);
}

我相信这比上面的片段更容易维护,但我知道我在DAO中为"utility"类引入了一个属性,它本身可能是一种代码气味(正如Ant p所指出的)。

摘要

这是一个艰难的决定——虽然我接受了Ant p的回答,但瓦迪姆的回答也是合理的。使用哪种方法取决于实用程序类,所有3种方法都有其用途(除了更新的#3)。至少这是我对所提供答案的看法。

  • 静态类确实有其用途,但也有许多缺点,如上所述
  • 正则类,按方法实例化:创建utility类,并在需要的地方使用它。减少依赖,保持你的类型纯粹
  • 正则类,实例化为member:当许多/所有方法都需要实用程序类的实例时,最好创建一个成员变量。通过这种方式,更改类型或实例化方式变得更容易

实用程序类:静态类与成员变量与局部变量

我会让那些更有资格的人对性能影响发表评论;然而,以下是我对每个问题的看法:

1.静态类

这个概念适用于简单、"不全面"的实用程序方法,这些方法不需要真正的可扩展性,但正如您所注意到的,您的公共DAO操作将变得更加复杂。作为一个单一的静态类,这不太可能是非常容易管理的,尤其是当它在多个不同类型的DAO中使用时。

2.具体类,每个DAO对象实例化

这一切都很好,但你真的需要实用程序类成为单个DAO的成员吗?如果您在DAO的整个生命周期中需要实用程序类中的某种一致性或状态持久性,我可以理解这一点,但这些方法似乎相当模糊(正如它作为"实用程序"类的名称一样)。

剩下3。具体类,按方法实例化对我来说,这似乎是最自然的解决方案。这让你可以灵活地利用你在问题中承认的具体类的所有优点,同时将对象的范围限制在需要的地方——单个方法调用。

如果你的类进化成整个DAO所需要的东西,例如你突然需要维护对象的状态(或者如果你需要将它注入DAO的构造函数,或者其他类似的东西),你总是可以更改它的实例化位置(尽管在我看来,如果发生这种情况,你就不再有实用程序类了,你需要重新考虑这个类如何适合你的体系结构)。

除非您计划创建大量这样的对象,否则我认为这不会影响性能。

我更喜欢(2)。只需为每次使用创建它,这就是免费编写代码。此外,如果你想使用某种IOC,可以将实用程序类作为参数,更改它的初始化方式,或者简单地将类更改为另一个类——只有一个成员可以更改比更改所有使用它的位置要容易得多。

除非你有一个很好的理由,否则远离静力学或辛格尔顿。(一个很好的例子是开发一个插件或插件,在其中你不能控制类的初始化和使用方式)。

当考虑静态类具体类

  • 实例类具有state、manage state,并且行为与它的内部状态相关,如果操作在某些方面与内部状态无关,那么这些确实是静态方法的候选者,但我稍后会详细介绍。这是封装的基础,并与SRP(单一责任原则)密切相关,SRP认为一个类应该有一个单一的责任,只做一件事,不做更多的事,所以,这给了你一个事实,即方法都与它的内部状态直接或间接相关

  • 静态类没有也不管理状态。也许有人会说这根本不是真的,看看单身汉。好吧,singleton可能很好,但设计为静态类的singleton太接近反模式了,在这种情况下,singleton可以像IoC容器一样进行管理,只管理一个实例。如果需要,我可以提供一些关于有容器和没有容器的例子。

有人说静态类是一种接近反模式的东西,因为例如可测试性。。好吧,这不是真的,这取决于静态类和测试的相关内容。我将通过一位伟大的软件架构师Udi Dahan报告一个非常好的例子,例如,在一篇关于域事件的好文章中,他谈到了其他事情,关于静态类和可测试性,如果你转到如何引发域事件用域事件进行单元测试一节,他会谈到这一点。

之后,正如你所说,两者的另一个区别是内存成本,但其他人也这么说。请记住,像Reshaper这样的工具建议将不处理状态的实例类/方法转换为静态表示,这有利于内存和使用。

关于您的设计的最后一句话:CommonDaoOperations似乎是一个真正的静态类,它不处理状态,所以它是静态类的一个很好的候选者,因为它是自然的,适合它所做的工作。相反,您可以使用IoC容器将其视为"singleton",并以正确的方式配置该类。有很多方法可以在没有容器的情况下以其他方式实现这一点。。这里有一篇关于Singleton和静态类的简单文章C#Singleton,StaticClass。当然,制作一个返回helper的属性不是一个好的设计,而为get操作返回新实例的属性总是一个坏的设计,这将有充分的理由。。。

因此,看到你的设计和如何使用helper类,Udi在上面的链接中说的话很好地描述了你应该实现的解决方案。