天天看点

三层架构--理论与实践一.理论篇:二.实践篇三.总结

    看视频的时候,开篇提出了很多的问题,这让我想起了“门卫定理”,你从哪里来,要到那里去,去干什么。学习本身就是这样,提出问题比解决问题更重要,带着问题学习,就会更加有目的性,注意力更集中。

一.理论篇:

1.三层架构是什么?有那三层,他们的顺序?

    三层架构是基于模块化程序设计的思想,为实现分解应用程序的需求,而逐渐形成的一种标准模式的模块划分方法。从上到下分别是表现层(Presentation layer),业务逻辑层(Business Logic Layer),数据访问层(Data access layer)。所谓三层体系结构,是在客户端与数据库之间加入了一个“中间层”

三层架构--理论与实践一.理论篇:二.实践篇三.总结

2.每一层的含义和功能,为什么分三层?

表现层:位于最外层(最上层),最接近用户。用于显示数据和接收用户输入的数据,为用户提供一种交互式操作的界面。

    UI设计原则是用户至上,兼顾简洁。

业务逻辑层:表示层和数据访问层之间沟通的桥梁,主要负责数据的传递和处理

    从DAL中获取数据,以供UI显示用

    从UI中获取用户指令和数据,执行业务逻辑

    从UI中获取用户指令和数据,通过DAL写入数据源

职责机制

    UI->BLL->UI

    UI->BLL->DAL->BLL->UI

数据访问层:也称为是持久层,其功能主要是负责数据库的访问,可以访问数据库系统、二进制文件、文本文档或是XML文档。

    从数据源加载数据(Select)

    向数据源写入数据(Insert/Update)

    从数据源删除数据(Delete)

三层架构--理论与实践一.理论篇:二.实践篇三.总结

三层的目的是实现“高内聚,低耦合”的思想,各层之间相互依靠接口连接,每一层的改变对其他层不会造成影响。

这样做的好处有:

    1.开发团队可以明确分工,统一代码格式,并行开发,提高效率。

    2.提高了系统的复用性,通过接口连接。

    3.使得系统更加健壮,系统的易于维护,如果一层出现了问题,只需要维护该层就可以了,同样降低了维护的成本。

    4.分层之后让系统更加清晰,把整体复杂的问题简单化。

3.什么时候需要三层?

    并不是所有的系统都要分三层或多层。任何事情都有两面性。过多的分层限制了限制了客户与开发人员的交流。由于层与层之间的引用关系,代码执行效率降低,会对系统的性能造成影响。 项目开发中具体问题要具体分析,盲目套用耦合反而会适得其反,不应分层而分层,不应模式而模式。对于业务逻辑简单,没有数据存储层的系统,就没有必要分层。

4.每一层的原则与层与层之间的引用?

DAL,BLL,UI分别在不同的程序集中。各层之间的引用关系如下:

    DAL所在程序集不引用BLL和UI

    BLL引用DAL

    UI直接引用BLL,可能间接引用DAL

    三层都引用实体层。

三层架构--理论与实践一.理论篇:二.实践篇三.总结

5.实体层怎么理解?

    实体层为了封装数据,为了数据在三层之间传输;对于大量的数据来说,用变量做参数不太合适 比如 把某个学生的所有信息传到下层,包括姓名 年龄 学号 班级...如果拿变量做参数,那在你的方法中起码有N个参数,很容易造成参数匹配上的错误,而如果拿实体对象做参数则方便的多,只要传一个学生实体就可以了,然后在方法里通过get(),set()属性获取或者设置实体对象里的成员属性值 。

    实体对象实际上是对应着数据库里的每张表的,我们把表里的字段封装在1个实体对象里,当想用哪个字段 ,就通过该实体对象的get() set() 把那个字段提取出来。这比临时创建1个变量要灵活的多,而且便于程序的维护和扩展。

    Model不知道外面的其他层次,独立于其他层次,不会引用任何层次的程序集。其他的三层都会引用Model,都知道Modul的存在;

二.实践篇

1.设计数据库Login:

数据表 主键 列名 数据类型 允许Null值
dbo.Scores ID int
UserName varchar(50)
Score int
dbo.Users ID int
UserName varchar(50)
PassWord varchar(50)
Email varchar(100) 允许

2.代码:

UI层

<span style="font-family:Courier New;font-size:14px;">namespace LoginUI</span><span style="font-size:14px;"><span style="font-family:Courier New;">
{
    public partial class Form1 : Form       //Partial:局部类型允许我们将一个类、结构或接口分成几个部分,分别实现在几个不同的.cs文件中。各个部分可以再不同的源文件中,源文件要有相同的命名空间;
    {
        public Form1()
        {
            InitializeComponent();<span style="white-space:pre">	</span>//初始化控件;
        }</span><span style="font-family:System;">
</span></span><span style="font-family:Courier New;font-size:14px;">
        private void btnLogin_Click(object sender, EventArgs e)
        {
            string UserName = txtUserName.Text.Trim();   //从文本框读入用户名,密码;   
            string PassWord = txtPassword.Text;     
            Login.BLL.LoginManager  mgr = new Login.BLL.LoginManager();  //实例化,开始转到BLL中。UI调用BLL层;
            //mgr.Login(UserName ,PassWord );
            
            try //异常处理程序,将可能发生例外的代码放到Try语句中,catch捕捉例外。与On error goto的不同点
            {
                Login.Model.UserInfo user = mgr.UserLogin(UserName, PassWord);

                MessageBox.Show("登录用户:" + user.UserName);
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}</span><span style="font-size:18px;">
</span>
           

BLL层

<span style="font-family:Courier New;font-size:14px;">namespace Login.BLL
{
    public class LoginManager       //类要设置为共有的才能访问;
    {
        public Login.Model .UserInfo  UserLogin (string UserName, string PassWord)   //User就是一个数据模型;上窜下蹦;需要额外的建程序集;//返回Model的UserInfo;
        {
            //throw new NotFiniteNumberException();
            //Login.DAL .UserDAO  uDAO =new Login .DAL.UserDAO ();
            //uDAO.SelectUser(UserName, PassWord);

            Login.DAL.UserDAO uDAO = new Login.DAL.UserDAO();       //类实例化一个对象;
            Login.Model.UserInfo user = uDAO.SelectUser(UserName, PassWord);

            if (user != null)       //登录成功
            {
                Login.DAL.ScoreDAO sDAO = new Login.DAL.ScoreDAO();
                sDAO.UpdateScore(UserName, 10);     //加10
                return user;
            }
            else
            {
                throw new Exception("登录失败");    //抛出异常
            }
        }
    }
}</span>
           

DAL层

<span style="font-family:Courier New;font-size:14px;">namespace Login.DAL
{
    public class UserDAO
    {
        public Login.Model .UserInfo  SelectUser(string UserName, string PassWord) //检验用户存在不存在,登录是否成功。“数据模型”
        {
            //throw new NotImplementedException();
            using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))   //连接
            {
                SqlCommand cmd = conn.CreateCommand();
                cmd.CommandText = @"SELECT ID,UserName,PassWord,Email FROM USERS WHERE [email protected] AND PassWord [email protected]";
                cmd.CommandType = CommandType.Text;     //指定如何解释命令字符串,text表示SQL 文本命令。
                cmd.Parameters.Add(new SqlParameter("@UserName", UserName));
                cmd.Parameters.Add(new SqlParameter("@PassWord", PassWord));

                conn.Open();
                SqlDataReader reader = cmd.ExecuteReader(); //针对 Connection 执行 CommandText,并生成 IDataReader。 
                Login.Model.UserInfo user = null;
                while (reader.Read())       //.Read()使 IDataReader 前进到下一条记录。
                {
                    if (user == null)
                    {
                        user = new Login.Model.UserInfo();
                    }
                    user.ID =reader.GetInt32(0);
                    user.UserName = reader.GetString(1);
                    user.PassWord = reader.GetString(2);<span style="white-space: pre;">	</span>//不需要从数据库中取;
                    

                    if (!reader.IsDBNull(3))
                    {
                        user.Email = reader.GetString(3);
                    }
                }
                return user;
            }
        }
    }
}</span><span style="font-size:18px;">
</span>
           

连接字符串

<span style="font-family:Courier New;font-size:14px;">namespace Login.DAL
{
    class DbUtil    //连接字符串
    {
        public static string ConnString = @"Server=fxq-PC;database=Login;user ID =sa ;PassWord=fxq";
    }
}</span>
           

登录成功则数据库中加10

<span style="font-family:Courier New;font-size:14px;">namespace Login.DAL
{
    public class ScoreDAO
    {
        public void UpdateScore(string UserName, int Value)
        {
            //throw new NotFiniteNumberException();
            using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))<span style="white-space: pre;">	//using的代码范围内你能使用conn这个对象,一旦你超出了using的代码范围,就没有conn可用;</span>
            {
                SqlCommand cmd = conn.CreateCommand();      //实例化命令对象
                cmd.CommandText = @"INSERT INTO SCORES(UserName,Score) values (@UserName,@Score)";
                cmd.Parameters.Add(new SqlParameter("@UserName", UserName));//给命令对象添加参数
                cmd.Parameters.Add(new SqlParameter("@Score",Value  ));

                conn.Open();                //不用关闭,因为用了Using。相当于在using块结束的时候手动调用conn.Dispose()方法</span><span style="font-family:Courier New;font-size:14px;">

                cmd.ExecuteNonQuery();      //对连接执行 Transact-SQL 语句并返回受影响的行数。
            }
        }
    }
}</span>
           

Entity(Model):为了封装数据,为了数据在三层之间传输;Model不知道外面的其他层次,独立于其他层次,不会引用任何层次的程序集。其他的三层都会引用Model,即都知道Modul的存在;

<span style="font-family:Courier New;font-size:14px;">namespace Login.Model         
{
    public class UserInfo
    {   //.NET3.0以后支持的写法;
        //public int ID { get; set; }
        //public string UserName{get ;set;}
        //public string PassWord { get; set; }
        //public string Email { get; set; }

        private int _ID;<span style="white-space: pre;">	</span>//更加安全;
        private string _UserName;
        private string _PassWord;
        private string _Email;

        public int ID
        {
            get { return _ID; }
            set { _ID = value; }
        }
        public string UserName
        {
            set { _UserName = value; }
            get { return _UserName; }
        }
        public string PassWord
        {
            set { _PassWord = value; }
            get { return _PassWord; }
        }
        public string Email
        {
            set { _Email = value; }
            get { return _Email; }
        }   
    }
}</span><span style="font-size:18px;">
</span>
           

三.总结

    了解三层,体会分层结构与不分层的区别和优势。加深对面向对象的思想的认识,实现解耦,懂得化难为简。理论结合实践,将分层做到灵活运用,不为分层而分层,不为模式而模式;