我有一个问题。
我刚刚在一家拥有一名“高级开发人员”的新公司开始工作。
在课堂上他正在这样做(例子):
class CarController{
public Cars GetCars(){
**Connection connect = new Connection(); // Create DB connection**
//and here some fetching of the data and returning it with a HTTP Response
}
public Cars GetCar(int id){
**Connection connect = new Connection(); // Create DB connection**
//and here some fetching the car with id, returning it with a HTTP Response
}
//and this pattern continues here...
}
我无法想象这是一个很好的做法,在每个方法中继续创建一个类的相同实例来调用数据库? 内存在各处创建实例是不是也不好?
在我看来,我们可以使用存储库模式,只允许访问实现接口的类的数据库类。 现在我们将Database类暴露给控制器,代码紧密耦合!
他说他无法理解存储库的概念,这就是为什么在这种情况下应该使用接口。
你如何说服一位大四学生重构代码,并向他证明他的编码没有良好的结构?
我如何以其他方式解释上述代码中的缺点?
答案 0 :(得分:3)
我无法想象,在每个方法中创建相同的类实例来调用数据库是一个好习惯吗?内存在各处创建实例是不是也不好?
在这种情况下,它实际上是 IS 的最佳做法。 .NET池数据库连接,因此创建它们通常不是一个昂贵的过程。但是,重用连接可能会导致问题。
但是,您应该在完成连接后立即处理连接。一个方便的方法是使用using
语句:
using(Connection connect = new Connection()) // Create DB connection
{
//and here some fetching of the data and returning it with a HTTP Response
} // the connection is closed and disposed of here.
在我看来,我们可以使用存储库模式,只允许访问实现接口的类的数据库类。现在我们将Database类暴露给控制器,代码紧密耦合!
当然,这可能是一种改进,但它与你的第一个问题正交。存储库应在需要时创建连接,并在完成后处理它。
你如何说服一位大四学生重构代码,并向他证明他的编码没有良好的结构?
如果你刚刚开始,如果你接近这种方式,你可能无法做到。请记住,大多数人(不论经验)都不喜欢别人批评他们的工作。相反,提供替代解决方案,并提供一些原因,说明为什么它是改进而非当前设计。一种务实的方法是提供一种情况,其中现有的模式会导致问题(单元测试是最明显的),并说明为什么不同的设计可以解决这个问题。
答案 1 :(得分:1)
在不使用IoC容器的情况下创建对象实例并不总是坏事(想象一下,如果我们每次想要创建string
时都使用Container.Resolve!)如果依赖项不是volatile dependency那么它可能不是DI的好选择。
反复创建和处理数据库连接并不昂贵(它们是从池中分配并保持打开状态),实际上被视为best practice。
在数据库连接的情况下,必须严格处理该连接并在快速时间范围内进行处理,因此有一个参数可以不注入它。您当然不希望调用者(或组合根)实例化连接,然后要求连接的使用者处理它;这违反了两个共同原则:
也许您可以注入数据库连接工厂,但这有点问题,因为IDBConnection
不包含SqlConnection
中找到的所有成员。因此,如果你想在这里使用DI,你需要提供一个具体的实例(顺便说一下,这是密封的,所以没有垫片),或者你需要从你的实现中剥离所有SQL专用的功能。 SqlCommand也是如此 - IDBCommand只有一小部分属性,而且根本没有异步方法。
它会让你松耦合吗?并不是的。你有一种假松散耦合,但数据访问类和SQL服务器数据库之间存在隐式逻辑耦合(例如,它们有一个共同的模式)。这不像你可以用OracleClient替换你的SqlClient并期望它能够工作。多年来我见过很多人尝试过它;如果你还在尝试,你还没有流行起来。它不起作用。功能丰富的数据库客户端将在数据库平台上具有一些硬依赖性。
单元测试会更容易吗?不确定。正如我上面提到的,你不能真正编写填充程序或存根,因为SqlConnection,SqlCommand,SqlParameter等都是密封的,并且都具有接口中找不到的具体方法。无论如何,你仍然会被嘲笑而不是顽固。
也许计划是在将来某个时候用EF替换所有那些低级SQL的东西。如果是这样的话,那么在此时将DI改装到DAL将是浪费时间,因为它最终都会被扔掉。
这是一个判断电话。你的同事有权成功。我会专注于其他更明显,更低级的重构结果。
答案 2 :(得分:-2)
向他解释" SOLID"设计原则。举例并解释接口和设计模式的使用。可能应该有点亮!
问他如何用他的代码完成单元测试!