您的位置:首页 > 其它

又一个“众所周知”的DAL层设计BUG

2011-05-14 10:48 471 查看
DAL层使用抽象工厂是大家再熟悉不过的设计方法了。最近在回顾项目的时候,发现网上流传的方法大多都存在一个不大不小BUG。对于整个系统而言,轻则需要重新更新配置,重则需要重启。

好了废话不多说,先看代码

private static void GetProvider()
{
try
{
_instance = (IDataProvider)Activator.CreateInstance(Type.GetType(string.Format("xxxx", ConnTypeString), false, true));
}
catch
{
_instance = null;
throw new Exception();
}
}

public static IDataProvider GetInstance()
{
if (_instance == null)
{
lock (_lockHelper)
{
if (_instance == null)
{
GetProvider();
}
}
}
return _instance;
}


我相信绝大多数的抽象工厂都是这样写的。因为设计模式的书上也是这样写的,网上能够找到的例子也是这样写的,许多大型项目(譬如DZNT)也是这样写的。

我为什么说这样的设计存在BUG呢?

这还要回到我们使用反射+配置文件+抽象工厂的DAL层的设计初衷。我们不希望把DAL使用何种数据库写死在代码中,而是希望灵活的切换数据库。回头看看代码,似乎没有发现什么问题。再细想“灵活切换数据”,在系统正在运行的时候切换数据库可以吗?答案是不可以。因为系统启动之后instance已经被初始化了,当你再次修改配置信息的时候就不会再次反射出新的instance。所以这里存在这样一个BUG。

修改之后的代码:

public static IDataProvider GetInstance()
{
string connType = Configs.GetConfigs().DbConfigInfo.ConnType;
if (_currentConnType != connType || _instance == null)
{
lock (_lockHelper)
{
if (_currentConnType != connType || _instance == null)
{
_currentConnType = connType;
GetProvider();
}
}
}
return _instance;
}

你在看完以后可以有种种理由反驳我

“我在修改配置文件的时候直接重置instance就可以了”
“我的程序只需要在启动的时候判断使用什么数据库就足够了,在运行时不会切换数据库”
“切换数据库必须保证数据安全,需要关闭系统,重新备份数据库再启动系统”

我并没有充足的理由回应你的驳斥。后两个观点更有理由让这个BUG存在。的确,在系统中我们没有必要考虑到每一个细节,只要能够让系统按照需求运行正常即可。所以我只想针对第一点说说我的看法。首先DZNT(老版本,新版代码未阅读)就是这样做的,提供了一个Reset重置instance。但这样设计似乎违背了“单一职责原则”,“一个类,最好只做一件事,只有一个引起它变化的原因”。所以在修改配置的时候就不应该去管DAL的事情,DAL的事情应该由DAL自己解决。同时也避免了在配置完数据库类型之后忘记Reset引起的BUG。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: