学习完三层之后对于三层有了大概的了解,结束了三层的学习便带着好奇来到了机房重构的学习当中。
在机房重构中第一问题就是要做“登录功能”,这个登录功能用到了七层的架构。
今天我们就来学习什么是七层,七层如何架构:
首先是一个七层架构的包图:
首先我们需要明确的了解各个层之间的功能和引用关系:
UI层 | 位于最外层,最接近用户,用于接收用户输入的数据,并且可以显示数据,为用户和计算机提供一种交互操作的界面 |
Facade层 | 为子系统中的一组接口提供一个一致的界面,应用了“外观模式”,外观层的作用就是作为U层和B层的枢纽,使得耦合度降低 |
BLL层 | 负责对数据的逻辑操作,对数据进行业务逻辑处理 |
IDAL层 | 是DAL层的接口 |
DAL层 | 数据访问层,主要对数据库或者文本文件,对数据库的操作具体为业务逻辑层或者表示层提供数据服务 |
Factory层 | 用于创建接口,返回接口,用到了抽象工厂+反射+配置文件,作用就是灵活的实现数据库的连接 |
Entity | 实现了对数据的封装,数据库中的每个表都对应一个实体类 |
引用关系:
UI层 | Facade层 Entity层
|
Facade层 | BLL层 Entity层 |
BLL层 | Entity层 Factory层IDAL层 |
Factory层 | IDAL层 |
IDAL层 | Entity层 |
DAL层 | IDAL层Entity层 |
U层:
namespace UI
{
public partial class LoginUI : Form
{
public LoginUI()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (UserName.Text.Trim() == "")
{
MessageBox.Show("请输入你的用户名!", "提示",MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
if (PassWord.Text == "")
{
MessageBox.Show("请输入你的密码!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
//实例化一个外观
Facade.LoginFacade Facade = new Facade.LoginFacade();
//实例化一个用户
Entity.UserInfo user = new Entity.UserInfo();
//接受信息
user.UserName = UserName.Text;
user.PassWord = PassWord.Text;
//调用外观方法,返回给user
Boolean flag = false;
Facade.LoginFacade FLogin = new Facade.LoginFacade();
flag = FLogin.SelectUser(user);
bool Flase = false;
//判断是否登录成功
if (flag != Flase)
{
MessageBox.Show("登录成功");
this.Hide();
this.DialogResult = System.Windows.Forms.DialogResult.OK;
Form a = new Form();
a.Show();
}
else
{
MessageBox.Show("用户名或密码不正确");
}
}
}
}
1.断文本框中是否有输入的内容
2.实例化一个用户(与Entity产生联系,并把用户名和口令赋值给这个实体)
3.实例化一个外观实例引用一个外观的方法(SelectUser) , 这个方法的返回值是一个逻辑值
有人会问:为什么要在U层中引用Facade层的方法
因为:外观层在七层中的主要作用就是作为U层和B层之间的枢纽,降低他们之间的耦合度。
Facade层
public class LoginFacade
{
//判断用户是否存在,并提供返回值flag
public Boolean SelectUser(Entity.UserInfo user)
{
bool flag;
//实例化逻辑类的一个实例
BLL.LoginBll userbll = new BLL.LoginBll();
flag = userbll.UserBll(user);
return flag;
}
}
因为要有逻辑判断 所以少不了逻辑层,于是在外观层中实例化一个逻辑类
外观层实例化BLL层,调用B层的方法 UserBll, 这个方法返回的是逻辑值。
Entity层:
public class UserInfo
{
//定义 用户ID
private int userid;
public int UserId
{
get { return userid; }
set { userid = value; }
}
//定义用户密码
private string password;
public string PassWord
{
get { return password; }
set { password = value; }
}
//定义用户类型字段
private string level;
public string Level
{
get { return level; }
set { level = value; }
}
//定义用户名字
private string username;
public string UserName
{
get { return username; }
set { username = value; }
}
}
BLL层:
public class LoginBll
{
public bool UserBll(Entity.UserInfo user)
{
//实例化工厂
Factory.LoginFactory fact = new Factory.LoginFactory();
//调用工厂方法创建接口
IDAL.LoginIDAL idal = fact.CreateUser();
//接受D层的返回值
DataTable table = idal.SelectUser(user);
bool flag;
if (table.Rows.Count == 0)//返回数据表类型,如果行数=0,说明没有符合该账号密码的用户
{
flag = false;
}
else
{
flag = true;
}
return flag;//返回数值,账号存在
}
}
因为进行逻辑判断用户是否存在 这个时候就需要有数据库了,需要连接数据库
在B层中实例化工厂层,并且调用工厂层的一个方法来创建连接数据库接口
Factory层:
public class LoginFactory
{
//获取配置文件
string StrDB = System.Configuration.ConfigurationManager.AppSettings["DB"];
//应用反射来获取DAL层操作
public IDAL.LoginIDAL CreateUser()
{
string ClassName = StrDB + "." + "LoginDal";
return (IDAL.LoginIDAL)Assembly.Load(StrDB).CreateInstance(ClassName);
}
}
工厂层:来创建接口,返回接口,用到了抽象工厂+反射+配置文件,
作用是灵活的实现数据库的连接
配置数据库之后 我们需要去D层判断数据
IDAL层:
namespace IDAL
{
//接口层
public interface LoginIDAL
{
//接口函数,判断要登陆的用户名是否在数据表中存在
DataTable SelectUser(UserInfo user);
}
}
D层:
访问类LoginDal
public class LoginDal : IDAL.LoginIDAL
{
public DataTable SelectUser(Entity.UserInfo user)
{
SqlHelper sqlHelper = new SqlHelper();
SqlParameter[] sqlparams = { new SqlParameter(@"UserName",user.UserName),new SqlParameter
(@"PassWord",user.PassWord)};
string sql = @"SELECT * FROM user_info WHERE userId=@UserName AND Pwd=@PassWord";//构造语句,匹配数据库表
DataTable dt = sqlHelper.ExecuteQuery(sql,sqlparams,CommandType.Text);
return dt;
}
}
操作类:SqlHelper类:
//数据访问层,数据操作类
public class SqlHelper
{
//定义数据库连接操作,指定在数据库上操作的类型
private SqlConnection conn = null;
private SqlCommand cmd = null;
private SqlDataReader sdr = null;
//数据库连接
public SqlHelper()
{
string connStr = ConfigurationManager.AppSettings["conStr"];
conn = new SqlConnection(connStr);
}
private SqlConnection GetConn()
{
if (conn.State == System.Data.ConnectionState.Closed)
{
conn.Open();
}
return conn;
}
///<summary>
///执行不带参数的数据库操作或者存储过程
/// 增删改查操作
/// 返回受影响的行数
///</summary>
public int ExecuteNonQuery(string cmdText, CommandType ct)
{
int res;
cmd = new SqlCommand(cmdText, GetConn());
cmd.CommandType = ct;
res = cmd.ExecuteNonQuery();
if (conn.State == System.Data.ConnectionState.Open)
{
conn.Close();
}
return res;
}
//执行带参数的数据库操作或者存储过程
public int ExecuteNonQuery(string cmdText, SqlParameter[] paras, CommandType ct)
{
int res;
using (cmd = new SqlCommand(cmdText, GetConn()))
{
cmd.CommandType = ct;
cmd.Parameters.AddRange(paras);
res = cmd.ExecuteNonQuery();
}
return res;
}
//执行不带参数的SqL查询语句或者存储过程
public DataTable ExecuteQuery(string cmdText, CommandType ct)
{
DataTable dt = new DataTable();
cmd = new SqlCommand(cmdText,GetConn());
cmd.CommandType = ct;
using (sdr = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection))
{
dt.Load(sdr);
}
return dt;
}
//执行带参数的SQL查询语句或存储过程
public DataTable ExecuteQuery(string cmdText, SqlParameter[] paras, CommandType ct)
{
DataTable dt = new DataTable();
cmd = new SqlCommand(cmdText, GetConn());
cmd.CommandType = ct;
cmd.Parameters.AddRange(paras);
using (sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
dt.Load(sdr);
}
return dt;
}
}
最后我们需要配置文件app. config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
</startup>
<appSettings>
<add key="DB" value="DAL"/>
<add key="conStr" value="server=DESKTOP-MJMH105;Database=CGNetCafe;User ID=sa;Password=123456"/>
</appSettings>
</configuration>
下面是我对七层整体步骤的一个梳理: