用非静态类封装静态类



我在看一个项目,发现了一些非常奇怪的东西。

有一个静态类,它有一组方法,每个方法都会调用远程服务器。

模板看起来有点像这样:

public static class DAI
public static ResponseObject ExecStatement(string db, string sql)
{
{ ... }
}
public static DataSetResponseObject GetDataSet(string db, string sql)
{
{ ... }
}
public static DataTableResponseObject GetDataTable(string db, string sql)
{
{ ... }
}
}

但是项目中没有任何位置调用此类。相反,它调用一个非静态类容器。

public class ExecSP : IExecSP
{
string _db;
public ExecSP(string db)
{
_db = db;
}
public ResponseObject OutputAsResponseObject(string sql)
{
return DAI.ExecStatement(_db, sql);
}
public ResponseObject OutputAsDataSet(string sql)
{
return DAI.GetDataSet(_db, sql);
}
public ResponseObject OutputAsDataTable(string sql)
{
return DAI.GetDataTable(_db, sql);
}
}

现在,我认为唯一的两个优点是,当封装在非静态容器中时,命名更加清晰,并且可以传递的参数更少。

但我想知道,从设计上来说,用非静态来封装静态类是否是个好主意?如果有的话,还有什么其他原因?因为我认为创建一个静态并调用它是可以的。但是,这个项目特意将所有静态类都封装起来;我不知道为什么。

我过去做过这样的事情,最常见的原因是如果静态方法是由第三方库提供的(即我没有编写它),但我不想编写直接依赖于该库的代码。在这种情况下,我将编写自己的类,并让它接受直接依赖关系。

假设我使用了一个接口(或者类似于您的示例中的接口),那么如果我决定使用不同的库,我可以编写另一个实现相同接口的类,并在运行时交换具体的类(使用类似于依赖注入的东西)。

在我看来,他们试图使对象可注入,以便使您的代码更易于测试和修改。

查看这篇文章:为什么要使用依赖项注入?

就我个人而言,我永远不会这么做,而是使用像Ninject或Unity这样的.NET依赖注入框架,以便在创建对象时将必要的引用注入到对象中。这样做有很多好处。。。对于初学者来说,您可以创建您的singleton对象,而不必实际使用静态成员,并且您可以对它们的生命周期有更多的控制。如果你想进行单元测试(你应该这样做),那么用一个模拟对象替换你的单例是很简单的,如果你后来决定单例可能不是最好的设计选择,那么注入一个作用域为其他对象(如主父视图模型等)的对象也是很简单的。您正在研究的项目可能正在使用该中间类来实现我所说的一些功能,但它永远不会像进行适当的依赖项注入那样灵活或干净。

这是一个标准模式。-包装一组更复杂的方法以隐藏其复杂性,例如一组只通过抛出异常返回错误的方法。-处理包装方法中的错误、异常等-将方法设置为静态,以防止诸如executeQueryByInt、executeQueryByLong、execute QueryByString等派生方法相乘。。。-将对SQL处理框架代码的引用的传播限制为仅封装的方法-重要在使用第三方静态库时,有一个单独的地方来记录如何调用、错误、特殊情况、错误解决方案

对于单元测试,单元测试应该实现一个简短的包装器类,该类只传递对静态类的调用。

无论多么简单,都不需要添加另一层复杂性来适应任意模式或对代码进行云计算。如果在单元测试中使用了额外的代码,那么生产代码就不应该实现额外的代码。

通常将库或nuget包单独封装在项目中,这样多解决方案项目就不会有几十个对第三方包的包引用。

奇怪的是Angular有桶的概念,然而.net核心却没有;一旦项目数量超过10个并且解决方案的使用年限超过2年,您就会进入Nuget Package h*ll。

静态方法和静态类多次重构了1000000多个line.net解决方案,使代码更容易在更大的上下文中移动。哪些最佳实践在较小的项目中能够很好地扩展,但在1000000多个线路系统中却不能很好地进行扩展。这是一种不同于玩具项目和博客文章的方法。这是关于能够看到什么代码被调用以及代码在哪里被调用,这样重构和简化就更容易了。

添加的类ExecSP没有任何好处。这两个方法都传入一个db字符串和一个sql字符串。我认为数据库字符串是数据库实例的某种连接字符串,sql是该实例要执行的原始sql字符串。在这种情况下,不妨直接调用DAI,因为没有理由使用包装器类。

从设计过程来看,这是紧密耦合。我们可能想通过创建一个实例,然后针对抽象运行一个命令,而不是传递连接字符串/sql语句,来减少数据库(IDatabase)。

Psudeo代码:

IDatabase dbInstance =  new DatabaseCreator(db);
dbInstance.Execute(sql); 

那么数据库是SQL Server、Oracle等也没关系。

抽象有助于测试。例如,在一个单元测试项目中,我可以编写自己的IDatabase实现,它甚至不使用数据库。我不确定在没有实际数据库实例的情况下如何测试它。如果我编写自己的测试实例,我就可以删除外部依赖关系。

最新更新