一、核心分层补充:BLL 层(业务逻辑层)
在原有分层基础上,BLL 层(Business Logic Layer) 是连接 UI 层与 DAL 层的核心中间层,负责处理核心业务逻辑,是分层架构中 "业务规则的执行者"。
-
核心职责:
-
接收 UI 层的请求,结合业务规则处理数据(如数据校验、权限判断、流程控制等);
-
调用 DAL 层获取或存储数据,不直接与数据库交互;
-
将处理结果返回给 UI 层(通常以 Model 层实体为载体)。
-
-
示例场景:
-
用户注册时,BLL 层验证 "用户名格式"、"密码强度"、"是否重复注册" 等业务规则,再调用 UserDAL 执行插入操作;
-
订单提交时,BLL 层处理 "库存扣减"、"金额计算"、"事务管理(确保库存和订单操作同时成功或失败)" 等逻辑。
-
二、各层依赖关系与引用规则
分层架构的核心原则是 "上层依赖下层,下层不依赖上层",具体引用关系如下:
层级 | 可引用的层级 | 不可直接引用的层级 | 说明 |
---|---|---|---|
UI 层 | BLL 层、Model 层 | DAL 层、IDAL 层 | UI 仅通过 BLL 获取数据,不直接操作数据库 |
BLL 层 | IDAL 层、Model 层 | UI 层、DAL 层 | BLL 依赖抽象接口(IDAL),不依赖具体实现 |
DAL 层 | Model 层、IDAL 层(实现接口) | UI 层、BLL 层 | DAL 是 IDAL 接口的具体实现 |
IDAL 层 | Model 层 | UI 层、BLL 层、DAL 层 | 接口层仅定义规则,不依赖任何实现 |
Model 层 | 无(独立) | 所有其他层 | 实体类是各层数据传递的 "载体" |
目的:通过严格的依赖规则实现 "松耦合",例如更换数据库时(如从 MySQL 改为 SQL Server),只需修改 DAL 层实现,BLL 和 UI 层无需变动。
三、IDAL 层与工厂模式(Factory)的配合
IDAL 层的核心价值在于 "依赖抽象而非具体",而工厂模式是实现这一目标的关键手段:
-
工厂模式作用:创建 DAL 层实例的 "中间件",使 BLL 层无需知道具体 DAL 类(如 UserDAL),只需通过工厂获取 IDAL 接口实例。
-
实现示例:
// 工厂类(Factory) public class DALFactory { // 根据接口类型创建对应DAL实例 public static IUser CreateUserDAL() { return new UserDAL(); // 若更换数据库,只需修改此处为NewUserDAL() } public static IProduct CreateProductDAL() { return new ProductDAL(); } } // BLL层调用方式(无需直接引用DAL) public class UserBLL { private IUser userDAL = DALFactory.CreateUserDAL(); // 依赖抽象接口 public void AddUser(User user) { // 业务逻辑校验 if (string.IsNullOrEmpty(user.Account)) { throw new Exception("用户名不能为空"); } userDAL.Add(user); // 调用接口方法 } }
-
优势 :当 DAL 层实现变化时(如从
UserDAL
改为UserDAL_MySQL
),只需修改工厂类,无需改动 BLL 和 UI 层,符合 "开闭原则"。
四、Model 层的扩展:实体分类
Model 层不仅包含数据库映射实体,还可根据需求细分为:
-
实体类(Entity):
-
与数据库表一一映射(如
User
对应Users
表,Product
对应Products
表); -
字段与表结构一致,用于 DAL 层与数据库的交互。
-
-
视图模型(ViewModel):
-
为 UI 层展示定制的数据模型,可能包含多个实体的组合数据;
-
示例:
UserDetailViewModel
包含User
的基本信息 +Order
的统计数据,供用户详情页展示。
-
-
数据传输对象(DTO):
-
用于跨层(尤其是分布式系统中)传输数据,可剔除敏感字段(如密码);
-
示例:
UserDTO
仅包含Id
、Account
、NickName
,用于 API 接口返回。
-
五、DAL 层的实现细节
DAL 层作为数据访问的 "执行者",需关注以下技术点:
-
数据库操作方式:
-
原生 SQL:通过
SqlConnection
、SqlCommand
执行 SQL 语句(灵活性高,适合复杂查询); -
ORM 框架:如 Entity Framework(EF)、Dapper,通过对象关系映射简化操作(开发效率高);
-
示例(Dapper 实现):
public class UserDAL : IUser { private string _connStr = "数据库连接字符串"; public User GetModel(int id) { using (var conn = new SqlConnection(_connStr)) { return conn.QueryFirstOrDefault<User>( "SELECT * FROM Users WHERE Id = @Id", new { Id = id } ); } } }
-
-
连接管理:
-
必须使用
using
语句或手动释放数据库连接,避免资源泄露; -
连接字符串应存储在配置文件(如
App.config
)中,而非硬编码。
-
六、通用层(Common):跨层工具集
为避免代码重复,可新增Common 层(类库),提供各层通用的功能:
-
包含内容:
-
工具类:如
StringHelper
(字符串处理)、DateTimeHelper
(日期转换); -
常量定义:如
DBConst
(数据库表名)、ErrorMsg
(错误提示); -
异常处理:自定义异常类(如
BusinessException
)、异常日志工具; -
配置管理:读取配置文件的工具类。
-
-
引用规则:所有其他层均可引用 Common 层,Common 层不依赖任何其他层。
七、分层架构的测试策略
分层架构的低耦合特性,使其易于单元测试:
-
UI 层:通过 UI 自动化测试框架(如 Selenium)测试用户交互;
-
BLL 层:使用单元测试框架(如 xUnit、NUnit),通过 Mock 工具(如 Moq)模拟 IDAL 接口的返回结果,无需依赖真实数据库;
// 测试UserBLL的AddUser方法(模拟IUser接口) [Test] public void AddUser_WhenAccountEmpty_ThrowException() { // 模拟IUser接口(不执行真实数据库操作) var mockUserDAL = new Mock<IUser>(); var userBLL = new UserBLL(mockUserDAL.Object); // 测试逻辑 var user = new User { Account = "" }; Assert.Throws<Exception>(() => userBLL.AddUser(user)); }
-
DAL 层:通过集成测试验证数据库操作的正确性(需连接测试数据库)。
八、命名规范与项目结构
为保证代码可读性,各层类 / 方法命名需遵循统一规范:
层级 | 命名规则示例 | 说明 |
---|---|---|
UI 层 | UserForm 、ProductPage |
窗体 / 页面以功能 + 类型命名 |
BLL 层 | UserBLL 、OrderBLL |
以实体名 + BLL 结尾 |
DAL 层 | UserDAL 、ProductDAL |
以实体名 + DAL 结尾 |
IDAL 层 | IUser 、IProduct |
接口以 I + 实体名开头 |
Model 层 | User 、Product 、UserDTO |
实体类直接用业务名称 |
方法 | AddUser 、GetProductById |
动词 + 实体 + 操作(如 Add、Get) |
九、分层架构的适用场景与挑战
-
适用场景:
-
中大型项目(团队协作、业务复杂);
-
需长期维护、可能频繁变更需求的项目;
-
需支持多数据库、多 UI(如同时有 WinForm 和 Web 界面)的项目。
-
-
潜在挑战:
-
小型项目可能因 "过度设计" 增加开发成本;
-
层次过多可能导致性能轻微损耗(可通过优化减少);
-
团队需严格遵守分层规范,否则可能出现 "层间越权"(如 UI 直接调用 DAL)。
-
十、C# 分层架构各层信息汇总表
层级 | 英文全称 | 类型 | 核心职责 | 依赖层级 | 典型命名示例 | 技术要点 |
---|---|---|---|---|---|---|
UI 层 | User Interface | 应用程序 | 展示数据、接收用户输入、调用 BLL 层处理请求 | BLL 层、Model 层 | UserForm.cs、ProductPage.xaml | 界面控件绑定、用户交互逻辑、数据展示格式化 |
BLL 层 | Business Logic Layer | 类库 | 处理业务规则(校验、权限、流程)、协调 DAL 层数据操作、返回结果给 UI 层 | IDAL 层、Model 层、Common 层 | UserBLL.cs、OrderBLL.cs | 事务管理、业务规则验证、依赖注入(通过接口调用 DAL) |
IDAL 层 | Interface Data Access Layer | 类库 | 定义数据访问接口规范,统一 DAL 层方法名称和参数 | Model 层 | IUser.cs、IProduct.cs | 接口继承(IBase)、方法签名标准化、不包含具体实现 |
DAL 层 | Data Access Layer | 类库 | 实现 IDAL 接口,直接与数据库交互(CRUD 操作) | Model 层、IDAL 层、Common 层 | UserDAL.cs、ProductDAL.cs | 数据库连接管理、ORM 框架(EF/Dapper)、SQL 语句优化 |
Model 层 | Model | 类库 | 定义数据实体,作为各层数据传递的载体 | 无(独立) | User.cs(实体)、UserDTO.cs(传输对象) | 实体与数据库表映射、数据注解(验证规则)、敏感字段过滤(DTO) |
Common 层 | Common | 类库 | 提供跨层通用工具和常量 | 无(被所有层引用) | StringHelper.cs、DBConst.cs | 工具类封装、异常处理、配置文件读取、日志记录 |
十一、C# 分层架构树状图(项目结构)
项目根目录/
├── UI/ // 用户界面层
│ ├── Forms/ // 窗体文件(WinForm)
│ │ ├── UserForm.cs // 用户管理窗体
│ │ └── ProductForm.cs // 商品管理窗体
│ ├── Pages/ // 页面文件(WPF/ASP.NET)
│ │ └── HomePage.xaml // 首页页面
│ └── Program.cs // 程序入口
│
├── BLL/ // 业务逻辑层
│ ├── UserBLL.cs // 用户业务逻辑处理
│ ├── ProductBLL.cs // 商品业务逻辑处理
│ └── OrderBLL.cs // 订单业务逻辑处理
│
├── IDAL/ // 数据访问接口层
│ ├── IBase.cs // 基础接口(通用方法)
│ ├── IUser.cs // 用户数据访问接口
│ ├── IProduct.cs // 商品数据访问接口
│ └── DALFactory.cs // 数据访问层工厂类
│
├── DAL/ // 数据访问层
│ ├── UserDAL.cs // 用户数据访问实现
│ ├── ProductDAL.cs // 商品数据访问实现
│ └── DBHelper.cs // 数据库连接辅助类
│
├── Model/ // 实体模型层
│ ├── Entity/ // 数据库实体类
│ │ ├── User.cs // 用户实体
│ │ └── Product.cs // 商品实体
│ ├── DTO/ // 数据传输对象
│ │ └── UserDTO.cs // 用户传输对象
│ └── ViewModel/ // 视图模型
│ └── ProductViewModel.cs // 商品视图模型
│
└── Common/ // 通用工具层
├── Helper/ // 工具类
│ ├── StringHelper.cs // 字符串处理工具
│ └── DateTimeHelper.cs // 日期时间工具
├── Const/ // 常量定义
│ └── DBConst.cs // 数据库相关常量
└── Exception/ // 异常处理
└── BusinessException.cs // 业务异常类
树状图说明:
-
各层以独立类库 / 项目存在,通过 "项目引用" 建立依赖关系
-
箭头方向为依赖方向(如 UI 层引用 BLL 层,BLL 层引用 IDAL 层)
-
工厂类(DALFactory)通常放在 IDAL 层或单独的 Factory 层,负责创建 DAL 实例,解除 BLL 与 DAL 的直接依赖