又一个“众所周知”的DAL层设计BUG
DAL层使用抽象工厂是大家再熟悉不过的设计方法了。最近在回顾项目的时候,发现网上流传的方法大多都存在一个不大不小BUG。对于整个系统而言,轻则需要重新更新配置,重则需要重启。
好了废话不多说,先看代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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。
修改之后的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异