最近进行了三层架构的学习,在进行三层架构学习之前我们心中就应该给自己提几个问题,什么是三层架构?我们为什么要使用三层架构,同样都是实现,我不使用三层架构去实现可以吗?三层架构有什么好处?这些问题我觉得应该贯穿在整个三层学习的过程中。
在三层结构之前就有两层结构,就是客户机(用户界面和应用逻辑) /服务器中间直接用sql语言去连接,三层结构是客户机(用户界面)/应用服务器(应用逻辑)/数据库服务器,这是三层架构物理上的划分。
什么是三层架构?
三层架构就是将整个业务应用划分为:表示层、业务逻辑层、数据访问层。
我们为什么要使用三层架构,同样都是实现,我不使用三层架构去实现可以吗?
使用三层架构就是为了符合“高内聚、低耦合”的思想,把各个功能模块划分为表示层、业务逻辑层、数据访问层、,各层之间采用接口互相访问,并通过对象模型的实体类作为数据传递的载体,不同的对象模型的实体类一般对应于数据库的不同表,实体类的属性与数据库表的字段名一致。
当然,不使用三层架构直接编写代码也同样可以完成我们想要的功能,但是,既然我们知道面向对象,知道写程序要符合高内聚低耦合的思想,所以有更好的为什么不去选择呢。
三层架构有什么好处?
开发人员分工更明确,将精力更专注于应用系统核心业务逻辑的分析、设计和开发,加快项目的进度,提高了开发效率,有利于项目的更新和维护工作。
各层介绍:
UI(表示层):主要是指与用户交互的界面。用于接受用户输入的数据和显示处理后用户需要的数据。
BLL(业务逻辑层):UI层和DAL层之间的桥梁。实现业务逻辑。业务逻辑具体包括验证、计算、判断、业务规则等等。
DAL(数据访问层):与数据库打交道,主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。(当然这些操作都是基于UI层的,用户的需求反馈给界面(UI),UI反馈给BLL,BLL反馈给DAL,DAL进行数据的操作,操作后再一一返回,直到将用户所需数据反馈给用户)
代码展示
Model层
namespace Login.Model//是为了封装数据,为了在三层之间传输数据,不会引用任何一个程序集,但是其他三个都引用他 { public class UserInfo { public int ID { get; set; } public string UserName { get; set; } public string Password { get; set; } public string Email { get; set; } } }
UI层:登录窗体
namespace LoginUI { public partial class Form1 : Form { public Form1() { InitializeComponent();//初始化窗体上所有控件 } private void btnLogin_Click(object sender, EventArgs e) { string userName = txtUserName.Text.Trim();//获得登录窗体的用户名,trim去空格 string password = txtPassword.Text;//获得登录窗体的密码 Login.Bll.LoginManager mgr = new Login.Bll.LoginManager();//实例化B层的对象mgr,让B层去判断输入内容 Login.Model.UserInfo user = mgr.UserLogin(userName, password);//和Model交互,将数据层的信息传入Model //提示登录成功 MessageBox.Show("登录用户:" + user.UserName); } } }
BLL层:登录管理员
namespace Login.Bll//业务逻辑层,要与数据访问层进行交互,调动数据库,从而判断用户输入的账户密码是否在数据库中存在 { public class LoginManager { //定义一个UserLogin的方法,返回值是login.Model.UserInfo类型的对象 public Login.Model.UserInfo UserLogin(string userName, string password) { //实例化一个DAL层的对象 Login.DAL.UserDAO uDao = new Login.DAL.UserDAO(); //通过UI层中填写的内容,调用SelectUser方法,返回相应的数据 Login.Model.UserInfo user = uDao.SelectUser(userName, password); if (user != null)//判断登录成功 { //实例化DAL层的一个加分对象 //登陆成功,与DAL层交互给此用户加10分,并返回user Login.DAL.ScoreDAO sDao = new Login.DAL.ScoreDAO(); sDao.UpdateScore(userName, 10); return user; } else { //登录失败则提示登陆失败 throw new Exception("登录失败。"); } } } }
DAL层:三个类
class Dbutil:用于保存连接数据库服务器的SQL语句
class ScoreDAO:访问数据库中score表插入积分
class UserDAO:访问数据库中user表用于判断是否存在此用户
Class Dbutil:
namespace Login.DAL //用于保存连接服务器的SQL语句 { class Dbutil { public static string ConnString = @"Database = 王梦杰; Database = Login; User ID = sa; Password = wangmengjie "; } }
Class ScoreDAO:
namespace Login.DAL { public class ScoreDAO { public void UpdateScore(string userName, int value) { //using方法自动关闭数据库连接 using (SqlConnection conn = new SqlConnection (Dbutil .ConnString ))//实例化了一个连接数据库的对象 { //在现有连接conn的基础上,创建一个命令用以执行SQL指令 SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = @"INSERT INTO SCORES(UserName, Score) Values(@UserName,@Score)";//插入积分 //把用户输入的内容保存到Parameters集合中 cmd.Parameters.Add(new SqlParameter("@UserName", userName)); cmd.Parameters.Add(new SqlParameter("@Score", value)); conn.Open();//打开连接 cmd.ExecuteNonQuery(); } } } }
Class UserDAO:
namespace Login.DAL { public class UserDAO { public Login.Model.UserInfo SelectUser(string userName, string password) { //using 是为了自动释放()里边的资源 using (SqlConnection conn = new SqlConnection(Dbutil.ConnString ))//实例化了一个连接数据库的对象,类似于一个开数据库的钥匙 { SqlCommand cmd = conn.CreateCommand();//在现有连接conn的基础上,创建一个命令用以执行SQL指令。 conn.Open();//连接(数据库的)打开 // CommandText:获取或设置要在数据源中执行的 Transact-SQL 语句、表名或存储过程。 cmd.CommandText = @"SELECT ID,UserName,Password,Email FROM USERS WHERE UserName=@UserName AND Password=@Password";//执行的select语句 //CommandType:获取或设置一个值,该值指示解释 CommandText 属性的方式。 cmd.CommandType = CommandType.Text;//CommandType是一个枚举类型,有三个值:text、StoredProcedure(存储过程)、TableDirect用于表示SqlCommand对象CommandType的执行形式,这里是text //把用户输入的内容存到Parameters集合中 cmd.Parameters.Add(new SqlParameter("@UserName", userName)); cmd.Parameters.Add(new SqlParameter("@Password", password)); SqlDataReader reader = cmd.ExecuteReader();//ExecuteReader :尽可能快地对数据库进行查询并得到结果。 //声明一个Login.Model.UserInfo 类型的对象user,只是声明 Login.Model.UserInfo user = null; while (reader.Read())//把数据库中读到的信息给user对象,返回给B层 { if (user == null) { user = new Login.Model.UserInfo();//实例化user } user.ID = reader.GetInt32(0); user.UserName = reader.GetString(1); user.Password = reader.GetString(2);//not suggestion if (!reader.IsDBNull(3)) { user.Email = reader.GetString(3); } } return user; } } } }
到这里相信大家都发现了,为什么要单独创建一个Dbutil类呢?
因为在Class ScoreDAO和Class UserDAO 这两个类中都需要连接数据库,而且连接数据库的语句还很长,所以我们把连接数据库的语句封装成一个类,用一个string类型的ConnString对象接收,之后需要连接数据库时只需要进行调用ConnString对象就可以了,面向对象里面的封装,提高了代码的复用性。
那么到此为止我们的三层架构已经分析完毕,期待下次的分享吧。