三层架构

C#三层架构详解

在网上收集的比较好的讲解三层架构的理解,我收集两部分,第一部分简单理解,第二部分比较详细。也有一些重复的地方

一、

C#三层架构登陆实例

 

很早之前,就听说过三层结构了。当时只知道 三层结构 是把 系统的 界面 数据库操作等不相关的程序分别开来。原来这么简单的实现,确实传说中的 三层结构啊。

首先,先来看一下是哪三层。表示层(UI,User Interface),业务逻辑层(BLL BusinessLogicLayer),数据访问层(DAL Data Access Layer)。三层的划分是物理上的划分。

表示层(UI),这个最容易理解,就是用户看到的主界面。

数据访问层(DAL),也不难理解,主要是负责数据的增删改查。

业务逻辑层(BLL),算是表示层和数据访问层的桥梁吧。里面主要存放一些业务流程。也就是逻辑。主要作用就是从DAL中获取数据,然后显示到UI上。

举一个例子,三层结构可以用饭店的实例来理解。

 

UI指的是服务员,BLL是厨师,DAL是采购员。

在顾客的眼里,只能看到服务员为他们服务。并不知道后台厨师和采购员是如何做的。对于上述三种不同的角色来说,无论哪个环节出了问题,只需要更换一个员工就可以照常营业的。

三层架构的优势,还是职责分离,降低耦合。

接下来,看一个使用三层结构的登陆实例。首先,需要声明一下。这个实例中有很多bug需要优化。不过对于展示三层的主要思想足够了。仅仅是一个实例而已。

数据库表:

 

这是数据模块图:

 

细心的读者肯定会发现,除了UI,BLL,DAL这三个之外还有一个Moudel存在,这个Moudel不属于任何一层,只是为了更好地链接三层而存在的。这个类只存储,与以上三类共同使用的东西。起一个协调的作用。Moudel类,也就是实体类。

下面是这几个层次的关系。

 

接下来需要看一下,他们分别是如何实现各自的分工的。

Entity类:

 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

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; }

    }

}

U层:

 

 

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;

 

namespace LoginUI

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void label1_Click(object sender, EventArgs e)

        {

 

        }

 

        private void btnLogin_Click(object sender, EventArgs e)

        {

            try

            {

                string userName = txtUserName.Text.Trim();   //取出用户界面的数据

                string password = txtPassword.Text;

                Login.BLL.LoginManager mgr = new Login.BLL.LoginManager();

                Login.Model.UserInfo user = mgr.UserLogin(userName, password);   //使用用户界面数据 进行查找

 

                //如果没有问题,则登陆成功

                MessageBox.Show("登陆用户:" + user.UserName);

            }

            catch (Exception ex)   //如果登陆有异常 则登陆失败

            {

                MessageBox.Show(ex.Message);

            }

        }

    }

}

B层:

 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace Login.BLL    //业务逻辑层

{

    public class LoginManager

    {

        public Login.Model.UserInfo UserLogin(string userName, string Password)

        {

            ///throw new NotImplementedException();

            Login.DAL.UserDAO uDAO = new Login.DAL.UserDAO();  //创建一个user

            Login.Model.UserInfo user= uDAO.SelectUser(userName, Password);  //通过ui中填写的内容 返回来相应的数据

 

            if (user!= null)        //如果数据库中没有数据,即为首次登陆了。增加10积分

            {

                Login.DAL.ScoreDAO sDAO = new Login.DAL.ScoreDAO();

                sDAO.UpdateScore(userName, 10);

                return user;

            }

            else       //如果数据库中没有该用户名,则登陆失败

            {                

                throw new Exception("登陆失败");

            }

        }

    }

}

 

D层:

 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace Login.DAL     //数据访问层

{

    class DbUtil        //用于保存 链接服务器的sql语句

    {

        public static string ConnString = @"Server=zc-pc;Database=Login;User ID=sa; Password=123456";

    }

}

 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Data;

using System.Data.SqlClient;

 

namespace Login.DAL

{

    public class UserDAO

    {

        public Login.Model.UserInfo SelectUser(string userName, string Password)   //根据 ui 选择返回一个user

        {

            using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))

            {

                //创建一个命令对象,并添加命令

                SqlCommand cmd = conn.CreateCommand(); 

                cmd.CommandText = @"SELECT ID,UserName,Password,Email FROM USERS WHERE UserName=@UserName AND Password=@Password";

                cmd.CommandType = CommandType.Text;

                cmd.Parameters.Add(new SqlParameter("@userName", userName));

                cmd.Parameters.Add(new SqlParameter("@Password", Password));

 

                conn.Open();        //打开数据链接

                SqlDataReader reader= cmd.ExecuteReader();

                 

                Login.Model.UserInfo user=null;     //用于保存读取的数据

 

                while (reader.Read())       //开始读取数据

                {

                    if (user==null)     //如果没有,则重新生成一个

                    {

                        user=new Login.Model.UserInfo();

                    }

                    user.ID=reader.GetInt32(0);

                    user.UserName=reader.GetString(1);

                    user.Password=reader.GetString(2);

                    if(!reader.IsDBNull(3))         //不要求一定要有email,也可以返回

                    {

                        user.Email=reader.GetString(3);

                    }                   

                }

                return user;

            }

             

        }

    }

}

 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Data.SqlClient;

 

namespace Login.DAL

{

    public class ScoreDAO     //首次登陆,增加10积分

    {

        public void UpdateScore(string userName, int value)

        {

            using (SqlConnection conn = new SqlConnection(DbUtil.ConnString))

            {

                SqlCommand cmd = conn.CreateCommand();  //创建一个命令对象

                cmd.CommandText = @"INSERT INTO SCORES(UserName,Score) Values(@UserName,@Score)";  //修改Score表数据

                cmd.Parameters.Add(new SqlParameter("@userName", userName));

                cmd.Parameters.Add(new SqlParameter("@Score", value));

 

                conn.Open();

                cmd.ExecuteNonQuery();

            }

        }

    }

}

接下来,看一下执行结果:

执行成功的情况:

 

输入错误信息:

 

虽然这是一个很小的实例,但是用来学习三层却足够了。有写的不好的地方可以理解。

总结:对于使用三层架构的程序来说,哪层出错改哪里。极大程度的降低了系统的耦合性。当然,具有层次的程序,维护起来必然要方便许多。

 -------------------------------------------------------------------------------------------------------------------------

二、

理解C#中得三层架构

       

  • 表示层
  • 业务逻辑层(BLL)
  • 数据访问层(DAL)

关联:产生依赖关系

描述:三层体系结构就是在客户端和数据库之间加一个中间层,通常情况下客户端不能直接和数据库进行交互,而是通过中间层和数据层进行交互的。

  【表示层】

    主要负责完成用户和系统的交互。

    它接收用户输入的信息,并把上级传来的处理结果表示给用户。盖层有时候兼容一小部分业务逻辑层的作用(验证用户输入的数据及其合法性)

    一般作为Windows或者Web应用程序

  【业务逻辑层】

    接收表示层传来的数据,以参数的形式传给数据访问层;然后接收数据层发来的处理好的数据,传给表示层。

    该层所做的工作比较复杂,如:实现业务流程、业务的数据校验

    是表示层和数据层之间的桥梁,都需要通过业务逻辑层来完成信息数据的收发

  【数据访问层】

    数据访问层为系统提供了规范,统一数据的访问入口,保证业务逻辑层对系统数据访问层的规范和高效,从而实现数据被高效、安全的访问

    该层会根据业务逻辑层的请求去处理和数据库之间的交互,不对数据做任何业务上的加工

【本人见解】

  表示层接受用户的请求,根据用户的请求去通知业务逻辑层,业务逻辑层收到请求,首先对请求进行审核,然后将请求发给数据访问层或者直接返回到表示层,数据访问层收到请求后就开始访问数据库,数据访问层通过数据库的访问得到请求的结果,并把结果通知业务逻辑层,业务逻辑层收到请求结果将请求结果通知表示层,表示层收到请求结果,然后把结果显示给用户;

  ps:用户登录系统就是这一应用的实例。

    用户输入账号密码---->表示层先判断,符合----->业务逻辑层进行封装--------->数据访问层进行进一步安全、高效的判断------->结果给业务逻辑层------->表示层显示结果

    这种传递是一步一步的进行下去,一步一步的回来,不能跨越传递。

 

 

在三层之间,各层之间是相互依赖的关系的,表示层依赖业务层逻辑,业务层依赖数据访问层,三层之间通过自身提供的对外方法来传递访问
三层之间的松耦合互不干扰,之间的联系是通过自己提供的接口来访问;
三层结构各层之间的的数据传递方法分为请求和响应两个方法;
项目依赖方向:先从表示层传递到业务层再到数据层;
数值返回:数据层返回给业务逻辑层,在由业务逻辑层返回给表示层,然后由表示层进行显示;

------------------------------------------------------------------------------------------

三层架构(我的理解及详细分析)

1什么是三层

  1. 2为什么使用三层
  2. 3与两层的区别
  3. 4三层的具体表现形式 

三层架构已经学了一段时间,一直想做一个比较完整、比较完美的总结。但是左思右想,不知道如何下笔。都说万事开头难嘛,今天整理了一下凌乱的思路,哎,还是没整理好,想到哪就说到哪吧。

 

初学者很不理解:

1,什么是三层?

2,为什么使用三层?

3,三层与以往使用的两层相比有什么不同?它的优势在哪里?

4,如何学好三层?如何应用三层?

……

这篇博客里我会给大家一一解释一下,略懂皮毛忘大家见谅!!!

米老师一直强调:让学习和生活结合,把学习和生活联系,这样的学习才叫会学习,会生活。

对于三层我左思右想,如何与实际相联系。好嘛,昨晚突然有了“灵感”。还记得大话设计模式里第23章大鸟和小菜吃羊肉串的故事——由在小摊吃到饭店吃引来的一个命令模式(当然今天不是研究命令模式)。服务员、厨师、采购员。

这不就是个典型的三层架构吗???(⊙ o ⊙ )啊!哈哈(这个后面再做解释)

 

 

 

先了解:

 

1,什么是三层?

UI(表现层):主要是指用户交互的界面。用于接收用户输入的数据和显示处理后用户需要的数据。

 

BLL:(业务逻辑层):UI层和DAL层之间的桥梁实现业务逻辑。业务逻辑具体包含:验证、计算、业务规则等等。

 

DAL:(数据访问层):数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。(当然这些操作都是基于UI层的。用户的需求反映给界面(UI),UI反映给BLLBLL反映给DALDAL进行数据的操作,操作后再一一返回,直到将用户所需数据反馈给用户)

 

每一层都各负其责,那么该如何将三层联系起来呢?

1>单项引用(见下图)

2>这时候实体层(Entity)来了。(注:当然,实体层的作用不止这些)

 

Entity(实体层):它不属于三层中的任何一层,但是它是必不可少的一层。

 

Entity在三层架构中的作用:

1,实现面向对象思想中的"封装";

2,贯穿于三层,在三层之间传递数据;

注:确切的说实体层贯穿于三层之间,来连接三层)

3,对于初学者来说,可以这样理解:每张数据表对应一个实体,即每个数据表中的字段对应实体中的属性(注:当然,事实上不是这样。为什么?1>,可能我们需要的实体在数据表对应的实体中并不存在;2>,我们完全可以将所有数据表中的所有字段都放在一个实体里)

4,每一层(UI—>BLL—>DAL)之间的数据传递(单向)是靠变量或实体作为参数来传递的,这样就构造了三层之间的联系,完成了功能的实现。

但是对于大量的数据来说,用变量做参数有些复杂,因为参数量太多,容易搞混。比如:我要把员工信息传递到下层,信息包括:员工号、姓名、年龄、性别、工资....用变量做参数的话,那么我们的方法中的参数就会很多,极有可能在使用时,将参数匹配搞混。这时候,如果用实体做参数,就会很方便,不用考虑参数匹配的问题,用到实体中哪个属性拿来直接用就可以,很方便。这样做也提高了效率。

 

注:这里为什么说可以暂时理解为每个数据表对应一个实体??答:大家都知道,我们做系统的目的,是为用户提供服务,用户可不关心你的系统后台是怎么工作的,用户只关心软件是不是好用,界面是不是符合自己心意。用户在界面上轻松的增、删、改、查,那么数据库中也要有相应的增、删、改、查,而增删改查具体操作对象就是数据库中的数据,说白了就是表中的字段。所以,将每个数据表作为一个实体类,实体类封装的属性对应到表中的字段,这样的话,实体在贯穿于三层之间时,就可以实现增删改查数据了)

 

综上所述:三层及实体层之间的依赖关系:

 

 

思想来源于生活:

 

 

 

服务员:只管接待客人;

厨师:只管做客人点的菜;

采购员:只管按客人点菜的要求采购食材;

 

他们各负其职,服务员不用了解厨师如何做菜,不用了解采购员如何采购食材;厨师不用知道服务员接待了哪位客人,不用知道采购员如何采购食材;同样,采购员不用知道服务员接待了哪位客人,不用知道厨师如何做菜。

 

他们三者是如何联系的?

比如:厨师会做:炒茄子、炒鸡蛋、炒面——此时构建三个方法( cookEggplant()cookEgg()cookNoodle())

 

顾客直接和服务员打交道,顾客和服务员(UI层)说:我要一个炒茄子,而服务员不负责炒茄子,她就把请求往上递交,传递给厨师(BLL层),厨师需要茄子,就把请求往上递交,传递给采购员(DAL层),采购员从仓库里取来茄子传回给厨师,厨师响应cookEggplant()方法,做好炒茄子后,又传回给服务员,服务员把茄子呈现给顾客。

这样就完成了一个完整的操作。

 

在此过程中,茄子作为参数在三层中传递,如果顾客点炒鸡蛋,则鸡蛋作为参数(这是变量做参数)。如果,用户增加需求,我们还得在方法中添加参数,一个方法添加一个,一个方法设计到三层;何况实际中并不止设计到一个方法的更改。所以,为了解决这个问题,我们可以把茄子、鸡蛋、面条作为属性定义到顾客实体中,一旦顾客增加了炒鸡蛋需求,直接把鸡蛋属性拿出来用即可,不用再去考虑去每层的方法中添加参数了,更不用考虑参数的匹配问题。

 

这样讲,不知道大家是不是可以明白。(待会实例解释吧)

 

2,为什么使用三层?

使用三层架构的目的:解耦!!!

同样拿上面饭店的例子来讲:

1)服务员(UI层)请假——另找服务员;厨师(BLL层)辞职——招聘另一个厨师;采购员(DAL)辞职——招聘另一个采购员;

2)顾客反映:1>你们店服务态度不好——服务员的问题。开除服务员;

2>你们店菜里有虫子——厨师的问题。换厨师;

 

任何一层发生变化都不会影响到另外一层!!!

 

3,与两层的区别??

两层:

 

 

(当任何一个地方发生变化时,都需要重新开发整个系统。“多层”放在一层,分工不明确耦合度高——难以适应需求变化,可维护性低、可扩展性低)

 

三层:

 

 

 

(发生在哪一层的变化,只需更改该层,不需要更改整个系统。层次清晰,分工明确,每层之间耦合度低——提高了效率,适应需求变化,可维护性高,可扩展性高)

 

综上:三层架构的

优势:1,结构清晰、耦合度低,2,可维护性高,可扩展性高;3,利于开发任务同步进行;容易适应需求变化

 

劣势:1、降低了系统的性能。这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。

2、有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码

3、增加了代码量,增加了工作量

 

4,三层的具体表现形式??

 

 

UI

 

(大家不要误会,UI层不只是一个个用户界面,也是需要有代码的)

 

 

(1,功能:用户输入数据、反馈给用户数据;2,大家观察代码:没有涉及到业务逻辑,直接传参、函数、方法调用,没有涉及到与数据库打交道的SQL语句和ADO.NET)

 

BLL

 

 

1BLL是表示层与数据访问层之间的桥梁,负责数据处理、传递;2,大家观察代码,没有涉及到界面上的控件,没有涉及到SQL语句和ADO.Net

 

DAL

 

 

 

 

 

 

 

 

(1,以上是DAL层中DbUtil类、user_DA类和workRecord_DA类中的代码;2,大家观察代码,没有涉及到界面控件,没有涉及到业务逻辑;只有与数据库打交道的SQL语句和ADO.net)

 

EntityModel)层:

 

(定义了实体类user

观察以上三层:

1,实体类user作为参数贯穿于三层之间;

2,通过传参、方法调用来实现功能;

3,各层之间各负其责;互不影响

 

对比两层结构,让大家深刻体会三层的极大好处:

还是以机房收费系统的登陆为例:

 

(观察上面的两层的代码:将业务逻辑、数据访问都展现在用户表现层,当需求需要改变时,需要改变整个系统。比如,我把文本框txtPassWord的名称改为txtPwd的话,大家观察一下得需要更改多少地方。这样的改动算是小的,如果真的有业务需求上的改动才叫麻烦复杂,程序员不跳楼才怪。呵呵、、开个玩笑)

与如此难以适应需求变化的两层相比,大家再次观察三层代码,再次思考,三层架构有什么好处呢?自己思考。。。。。

 

自己去发掘吧!!!

 

转载于:https://www.cnblogs.com/bb-love-dd/p/6014698.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值