浅析“三层”架构
long long ago,我们的前辈们在写软件的时候开始也是只要完成功能就行了,但是随着时间的推移,以前的有些功能可能已经不适用了,就产生了“修改需求”,也可能由于社会的进步,软件的功能不够用了,需要加些“新东西”上去……无论怎样,都是要修改以前写好的软件了,但是在修改的时候又发现,以前实现功能部分的代码比较零散,无从下手,还会发现好不容易改好了,原来的功能却出了问题,等等,那么怎么才能使软件变得有条理些?或者说方便快速高效的开发?
一、什么是三层?
我们从现实生活寻找答案,原来的作坊式公司生产一辆车,他必须找个精通工艺的人,这个人需要自己构思,自己设计,自己制造零件,然后自己组装,自己测试——和我们传统的开发模式一样。当有一天这个车出了问题,一般得当时制造他的人来才会修理——软件变得不可维护。更不要说新加功能了,别人拿这车什么也不敢动——可扩充性变差,而且当时制造的周期也太长了——开发效率低,如果有一个零件设计的不合适这个车就报废了——健壮度差,所以那种汽车公司基本倒闭了,现在看到的是5分钟出一辆的宝马生产线,他的效率和合格率为什么这么高呢?我们一起来分析一下他们成功的原因:
分工:每个人只管自己的事情,负责的范围小了,质量和效率当然高了,就算这个人离职了,新招一个人可以很快熟悉这个岗位。
规范:大家按照同一个标准,我不需要亲自量你的零件就可以知道是装在哪的
其实这就是我们今天要说的分层思想
那软件中的三层是怎么分出来的呢?
我们一般认为项目类软件都涉及到和用户交互,数据库访问,业务的处理三个方面,这三个方面基本可以把一个项目类软件的共性给概括出来,所以一般我们就按照这个把软件分成三个层次:
表示层:负责和客户交互,和界面的关系比较大,当然表示层还承担着传递客户需求和展示操作结果的职责;
业务逻辑层:负责处理客户的业务,即把一个大的操作分解成很多小的操作来实现,涉及到循环就循环,涉及到判断就判断,对数据进行一个加工处理;
数据访问层:就像他的名字,专门管数据访问用,他不需要关注查出的数据被谁用了,也不需要关注谁给他的数据,只需要知道和数据库把关系搞好就OK了
这样一分之后呢,思路就清晰多了,新增需求了,界面还是业务?如果是界面,只改表示层,如果是业务,要不要修改数据库?等等,需要修改或增加哪里非常明确。再或者说把CS的程序放到互联网上访问,那么只需要更改表示层的访问方式即可
注意:我们所谓的改不全是修改原有代码,这样是违背我们的开闭原则的
二、如何搭建三层?
我们发现这样一“分工”之后软件的条例变得清晰了,下来我们就来实际演示下怎么分,分了之后怎么调用:
1. 新建一个应用程序或者WEB项目:假设项目名为Test,就作为我们的表示层; 2. 在解决方案管理器上右键新建项目,选择一个类库,起个名字叫Test.BLL,作为我们的业务逻辑层(BLL是业务逻辑层的简写形式,纯粹是一个约定); 3. 在解决方案管理器上右键新建项目,选择一个类库,起个名字叫Test.DAL,作为我们的数据访问层(注意中间的点是英文输入法下面的,现在加点是为了理解方便); 4. 添加引用:在表示层的引用上面右键选择添加,再次选择项目,找到Test.BLL确定即可,在业务逻辑层的引用上面右键选择添加,找到test.DAL确定即可 |
现在就可以重新编译一遍以确定操作中没有出现错误。
框架搭建起来之后,就可以开始我们的开发了,但是在开发之前需要做一些约定,原因很简单,软件分层了,我们怎么很容易的知道哪个类是属于哪个层的?
约定如下:
业务逻辑层类名:表名+Manager 数据访问层类名:表明+Service |
详细搭建过程如下:
1. 创建表:
create table Student ( StuId int identity(1,1) primary key, StuName varchar(20) not null, StuAge int not null ) |
2. 插入测试数据:
insert into student(StuName,StuAge)values('张三',18) insert into student(StuName,StuAge)values('李四',20) |
4. 在解决方案上右键添加新项目,选择类库(业务逻辑层:名称是项目名.BLL)如:
创建好之后解决方案管理器中应该是:
6. 添加各个层次的引用(表示层引用业务逻辑层,业务逻辑层引用数据访问层),添加方式如:在表示层的“引用”上右键
选中业务逻辑层BLL,同理添加业务逻辑层对数据访问层的引用
到此,我们的三层就搭建完毕。
三、如何实现三层?
下来我们采取实例来学习实际使用,我们先来完成一个根据ID查询姓名的功能,完成步骤如下:
1. 在数据访问层添加学生类(StudentService),添加相关数据库访问代码如:
/// <summary> /// 数据访问层学生类 /// </summary> public class StudentService { /// <summary> /// 根据ID查询姓名 /// </summary> /// <param name="id">学生ID</param> /// <returns>姓名</returns> public string GetNameById(int id) { string conStr = "server=.;database=bank;uid=sa;pwd=accp"; SqlConnection con = new SqlConnection(conStr);//建立连接 con.Open(); string sql = "select stuname from student where stuid="+id; SqlCommand cmd = new SqlCommand(sql,con);//命令执行官对象 string name = cmd.ExecuteScalar().ToString();//返回第一行第一列的值 con.Close(); return name; } } |
2. 在业务逻辑层添加学生类(StudentManager),注意要引入数据访问层的命名空间
//引入数据访问层命名空间:using Stu.DAL; /// <summary> /// 业务逻辑层问层学生类 /// </summary> public class StudentManager { StudentService studentService = new StudentService(); /// <summary> /// 根据ID查询姓名 /// </summary> /// <param name="id">学生ID</param> /// <returns>姓名</returns> public string GetNameById(int id) { return studentService.GetNameById(id); } } |
在按钮的点击事件下写如下代码:
//需要引入业务逻辑层的命名空间using Stu.BLL; StudentManager studentManager = new StudentManager();//实例化业务逻辑对象 string name = studentManager.GetNameById(int.Parse(txt_id.Text)); MessageBox.Show(name); |
四、三层如何工作?
接下来我们研究下具体的执行过程,当我们在界面(表示层)输入一个查询条件,表示层接到这个信息之后会把这个请求转给业务逻辑层,业务逻辑层又把这个请求转给数据访问层,数据访问层自己去数据找数据,找到之后原路返回。如此数据的整个流程可以表示为:
好了,弄清楚这些我们在来一个注册功能,即插入,设计界面如下:
1. 在数据访问层添加方法如下:
/// <summary> /// 学生注册功能 /// </summary> /// <param name="name">姓名</param> /// <param name="age">年龄</param> /// <returns>影响行数</returns> public int AddStudent(string name, int age) { string conStr = "server=.;database=bank;uid=sa;pwd=accp"; SqlConnection con = new SqlConnection(conStr);//建立连接 con.Open(); string sql =string.Format( "insert into student(StuName,StuAge)values('{0}',{1})",name,age); SqlCommand cmd = new SqlCommand(sql,con); int i = cmd.ExecuteNonQuery(); con.Close(); return i; } |
2. 在业务逻辑层添加方法如下:
/// <summary> /// 学生注册功能 /// </summary> /// <param name="name">姓名</param> /// <param name="age">年龄</param> /// <returns>影响行数</returns> public int AddStudent(string name, int age) { return studentService.AddStudent(name,age); } |
3. 在表示层注册按钮下添加代码如下:
StudentManager studentManager = new StudentManager();//实例化业务逻辑对象 int i = studentManager.AddStudent(txt_name.Text,int.Parse(txt_age.Text)); if (i > 0) MessageBox.Show("OK"); |
五、总结
好了,今天基本的三层到此就已经搭建好,并且举例说明了用法,当然,现在的用法很不完善,和我们实际开发中使用的三层还是有很大一段距离的,最基本的比如没有加入面向对象的思想,数据库限制比较大等,后面我们继续学习安全访问和高效访问。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端