"经典 3 层架构" VS ".net core现代化版本"
先用你熟悉的方式对应一下
- 以前的
UI层= 现在的CustomerManager.WinForms - 以前的
Business= 现在拆成了CustomerManager.Application+CustomerManager.Domain - 以前的
DAL= 现在主要是CustomerManager.Infrastructure
你可以先这样记:
WinForms:界面层,负责按钮点击、表单输入、列表显示Application:业务编排层,负责"这个功能怎么走"Domain:核心业务模型层,负责"客户是什么、客户有哪些规则"Infrastructure:数据访问和技术实现层,负责"数据到底存哪、怎么取"
所以它不是推翻你以前的 3 层,而是把以前那个偏大的 Business 又拆细了一点。
和经典 3 层最接近的映射
- UI层 :
src/CustomerManager.WinForms - Business层
- 偏"业务流程"的部分:
src/CustomerManager.Application - 偏"业务对象/规则"的部分:
src/CustomerManager.Domain
- 偏"业务流程"的部分:
- DAL层 :
src/CustomerManager.Infrastructure
如果按你过去的习惯看:
Application很像以前的BLLInfrastructure很像以前的DALDomain相当于把"实体类、接口、规则"单独抽出来了
为什么要把 Business 再拆成两个 以前很多项目里,Business 会越写越大,里面混着这些东西:
- 实体类
- 业务规则
- 功能流程
- 调 DAL
- 工具类
现在一般会拆成两块:
-
Domain- 放"最核心、最稳定"的东西
- 比如
Customer实体、ICustomerRepository接口 - 不关心 WinForms、数据库、日志这些技术细节
-
Application- 放"用例流程"
- 比如"新增客户""修改客户""删除客户"
- 它调用
Domain里的接口去做事
这样好处是:
- 业务模型更稳定
- UI 和数据库变化时,不容易把核心逻辑搞乱
- 后面换存储方式也方便
你现在这个项目里,每层到底干什么
-
src/CustomerManager.WinForms- 就是窗体层
- 例如
CustomerListForm、CustomerEditForm - 只做界面交互,不直接写业务逻辑,不直接访问数据库
-
src/CustomerManager.Application- 就是"业务服务层"
- 例如
CustomerAppService - Form 点按钮后,主要调用这里的方法
-
src/CustomerManager.Domain- 就是"业务模型层"
- 例如
Customer、ICustomerRepository - 定义系统里"客户"是什么,以及仓储接口长什么样
-
src/CustomerManager.Infrastructure- 就是"数据实现层"
- 例如
InMemoryCustomerRepository - 现在先用内存模拟数据,后面可以替换成
EF Core + SQLite
如果按"新增客户"流程看,就很清楚了 用户在界面点"新增客户"后,流程大概是:
CustomerEditForm收集输入- 调用
ICustomerAppService.CreateAsync(...) CustomerAppService创建Customer实体,并调用ICustomerRepositoryInMemoryCustomerRepository把数据存起来- Service 返回结果
- Form 再刷新列表
也就是:
Form -> Service -> Repository
这其实和你以前的:
UI -> BLL -> DAL
是同一条路,只是命名更现代,职责更细。
那 DI 是什么,为什么现在到处都在用 以前 WinForms 很常见的写法是:
var service = new CustomerService();
var dal = new CustomerDal();
现在更常见的是"不自己 new,而是交给容器创建",这就是 DI。
比如现在可能是这样:
Form需要ICustomerAppService- 容器自动把
CustomerAppService注入进去 CustomerAppService需要ICustomerRepository- 容器再把
InMemoryCustomerRepository注入进去
这样做的好处:
- 各层不直接绑死实现类
- 后面把内存仓储换成数据库仓储,不用改 Form
- 更方便测试
你可以把 DI 理解成:
- 以前:自己手动
new - 现在:启动时统一登记,运行时自动给你装配
那 Program.cs 为什么变复杂了 以前 WinForms 的 Program.cs 很简单:
Application.Run(new Form1());
现在它变成了应用启动入口,除了开窗体,还负责:
- 注册 DI
- 加载配置
- 初始化日志
- 创建主窗体
所以 src/CustomerManager.WinForms/Program.cs 现在像一个"总装配点"。
你可以把它理解成:
- 以前只是"启动窗体"
- 现在是"先把整个系统零件装好,再启动窗体"
AppSettings.cs 是干什么的 你刚打开的 src/CustomerManager.WinForms/Configuration/AppSettings.cs,本质上是"配置项对应的 C# 类"。
比如配置文件里可能有:
{
"AppSettings": {
"AppName": "Customer Manager"
}
}
那 AppSettings.cs 就是把这段配置映射成对象,代码里就可以类型安全地用,而不是到处写字符串读取配置。
你可以把它理解成:
- 以前可能写在
app.config/web.config - 现在常用
appsettings.json - 再配一个
AppSettings类接它
也就是"配置实体类"。
日志又是怎么回事 以前很多 WinForms 项目会自己写:
- 文本日志
- Log4Net
- 或者干脆不记日志
现在 .NET 统一用了 ILogger<T> 这一套抽象。 好处是:
- 代码里统一写日志接口
- 底层想输出到控制台、Debug、文件,都可以后面换
所以它和 DI 一样,也是"先抽象,再注入"。
MVP 你不用现在就紧张 你提的"复杂窗体以后演进到 MVP"是对的,但这里不是说所有窗体都必须马上上 MVP。
你可以先这样理解:
- 简单窗体:
Form + Service - 复杂窗体:
Form + Presenter + Service
也就是说:
- 简单页面先按你熟悉的方式写
- 只是别把业务逻辑直接塞进 Form
- 当列表页越来越复杂,再把它提炼成 MVP
这是一种"渐进升级",不是一开始就把 WinForms 写成很重的模式。
如果用你熟悉的话来重新描述这个项目 你完全可以先这样理解当前骨架:
WinForms= UI 层Application= BLLInfrastructure= DALDomain= 实体层 + 接口层 + 业务规则层Program.cs= 系统启动装配入口AppSettings.cs= 配置实体类DI= 自动帮你 new 对象并串起来
这么看就不会陌生了。
最重要的一句话 这套结构不是"和你以前完全不一样",而是:
- 保留你熟悉的
UI -> Business -> DAL思路 - 再把
Business拆得更清楚 - 再把"对象创建、配置、日志"标准化了
如果你愿意,我下一条可以继续直接按"你熟悉的 3 层思维"帮你画一张这个项目的对照图,比如:
- 哪个项目相当于以前的 BLL
- 哪个类相当于以前的 DAL
- 一个新增客户按钮点击后,代码会怎么流转
我可以专门用"老 WinForms 开发者视角"给你讲一版。