我最近开始在一个新项目中工作,我们有数千行遗留代码。我们正面临几个性能问题。我决定看看代码并看到以下内容。有一节课:
public class BaseDataAccess
{
private Database dB;
public Database DB
{
get
{
if (dB == null)
{
dB = DatabaseFactory.CreateDatabase();
}
return dB;
}
}
}
许多继承自前一个基类的后代类。在内部,其他类使用DB属性,如下所示:
DataSet ds = DB.ExecuteDataSet(spGetCustomersSortedByAge);
最后,有一个庞大的类(5000行代码),有如下几种方法:
public void ProcessPayments()
{
try
{
List<Employee> employees = new EmployeesDA().SelectAll(null);
foreach (Employee employee in employees)
{
employee.Account = new MovementsDA().SelectAll(employee.Id, DateTime.Now);
...
City city = new CitiesDA().Select(zone.cityId);
...
Management m = new ManagmentDA().Select(city.id);
}
}
catch (Exception ex)
{
...
}
}
在上一个方法中注意,EmployeesDA,MovementsDA,CitiesDA和ManagmentDA都是BaseDataAccess的继承者,并在内部使用它们各自的DB属性。还要注意它们在foreach循环中不断被实例化(在嵌套的2个级别内多次)。
我认为实例化本身是可疑的,但我更担心这里的数据库连接发生了什么?是否每个DA实例化都会打开一个新的底层连接?这段代码有多糟糕?
作为关于解决方案的旁注,我正在考虑以防这个代码应该修复:我正在考虑使每个构造函数都是私有的,因此编译器开始抱怨实例化并通过调用GetInstance方法重构实例化(单例模式)避免重新创建对象和底层连接。但是,我不确定这在某种程度上是否也会有危险,例如,如果连接可能会关闭。由于实例化一直在发生,当前的代码没有这个问题。
答案 0 :(得分:0)
对象构造昂贵是一种常见的误解。它比基本算术或其他机器级别的东西贵得多,但不太可能是性能问题的直接来源。
例如,对循环使用盒装整数是浪费的,但是在每个中构造一个Employee对象与重用可变的Employee对象并不会带来有意义的性能优势。
许多垃圾收集器能够像这样在循环中重用对象内存帧。实际上,在循环的每次传递中分配并覆盖单个对象帧。
在这种特定情况下,如果DA具有显着的初始化成本,则可能存在成本。如果是这种情况,我会重构代码以在循环之外创建那些代码。我不会使用实际的静态单例。如果需要,我会使用依赖注入来管理单例对象。静态单例是有效的全局变量,是对有状态耦合和模块化破坏的邀请。