前言

   前段时间朋友拿了个网站给我,让我帮忙添加几个小功能,我爽快的答应了,但是当我打开源码,我瞬间就奔溃了,整个项目连最基本的三层框架也没有搭建,仅仅是封装了一个sqlhelp作为数据库的操作接口,项目中的SQL查询语句无处不在,业务逻辑紧紧耦合在UI逻辑中,看到这样的代码,坦白来说,我什么兴致都没有了,但是碍着人情,我硬着头皮,把基本功能的完成交差,通过这件事情,我对软件分层进行了深入的思考。

三层架构

  说到三层架构,大伙都很熟悉,我也不再多啰嗦了,我们直接快速搭建一个。

项目的引用关系是:StructWed->BLL,Model;BLL->DAL,Model;DAL->Model。下面我们来演示一下程序流程,假设我们的数据库有一张订单表Order表,我们的业务是针对Order表进行的增删改查,那么根据三层架构的编程模式,我们就需要建立起对应的Model层实体,数据访问层实体和业务层实体,我们分别用OrderModel,OrderDAL,OrderBLL表示,代码如下,由于仅仅是为了演示,所以我并未提供相应的实现。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace Mode
{public class OrderModel{public int ID { get; set; }public int productName { get; set; }public DateTime CreateTime { get; set; }}
}

View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mode;namespace DaL
{public class OrderDAL{/// <summary>/// 向Order表插入数据/// </summary>/// <returns>成功:true,失败:false</returns>public bool Insert(){return true;}/// <summary>/// 修改Order表数据/// </summary>/// <param name="model">表数据对应实体</param>/// <returns>成功:true,失败:false</returns>public bool Update(OrderModel model){return true;}/// <summary>/// 删除Order表指定ID的记录/// </summary>/// <param name="id">表ID</param>/// <returns>成功:true,失败:false</returns>public bool Delete(int id){return true;}}
}

View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DaL;
using Mode;namespace Bll
{public class OrderBLL{protected OrderDAL orderDal = new OrderDAL();public bool Insert(OrderModel model){//业务点1//业务点2return orderDal.Insert();}/// <summary>/// 修改Order表数据/// </summary>/// <param name="model">表数据对应实体</param>/// <returns>成功:true,失败:false</returns>public bool Update(OrderModel model){//业务点1//业务点2return orderDal.Update(model);}/// <summary>/// 删除Order表指定ID的记录/// </summary>/// <param name="id">表ID</param>/// <returns>成功:true,失败:false</returns>public bool Delete(int id){//业务点1//业务点2return orderDal.Delete(id);}}
}

View Code

  好了,现在让我们把目光聚焦到OrderBLL上面来。我们发现OrderBLL对数据库Order表的所有操作都是在调用其内部创建的orderDAL实体的同名方法,换句话来说OrderBLL指示其内部orderDAL实体去完成数据库的增删改查。

  好现在,我们思考一下。假设有一天我们发现我们数据访问层的orderDAL实体代码写的很不优雅,效率极差,我们想用一个更优雅的实体,比如OrderActiveDAL去替换掉它,那么这个时候我们OrderBLL的代码就必须做相应的改动,如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DaL;
using Mode;namespace Bll
{public class OrderBLL{protected OrderActive orderActive = new OrderActive();public bool Insert(OrderModel model){//业务点1//业务点2return orderActive.Insert();}/// <summary>/// 修改Order表数据/// </summary>/// <param name="model">表数据对应实体</param>/// <returns>成功:true,失败:false</returns>public bool Update(OrderModel model){//业务点1//业务点2return orderActive.Update(model);}/// <summary>/// 删除Order表指定ID的记录/// </summary>/// <param name="id">表ID</param>/// <returns>成功:true,失败:false</returns>public bool Delete(int id){//业务点1//业务点2return orderActive.Delete(id);}}
}

View Code

这显然不是一种好的处理方式。我们追求的是在替换orderDal实体的同时,不修改OrderBLL的任何代码,换句话说就是解除BLL层与DAL层的耦合,为了达到这个目的,我们添加一个叫IDAL的接口类库,如图

特别注意,我们在BLL层中添加了对IDA的引用,同时移除了对DAL的引用,这就意味着我们在BLL中无法创建(new)DAL层中的任何实体。下面我们在IDA项目中定义IOrder接口,如下

using Mode;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace IDal
{public interface IOrder{/// <summary>/// 向Order表插入数据/// </summary>/// <returns>成功:true,失败:false</returns>bool Insert();/// <summary>/// 修改Order表数据/// </summary>/// <param name="model">表数据对应实体</param>/// <returns>成功:true,失败:false</returns>bool Update(OrderModel model);/// <summary>/// 删除Order表指定ID的记录/// </summary>/// <param name="id">表ID</param>/// <returns>成功:true,失败:false</returns>bool Delete(int id);}
}

View Code

我们让DAL引用IDAL,同时让OrderActiveDAL,OrderDal分别实现IOrder接口,如下

using IDal;
using Mode;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace DaL
{class OrderActiveDAL : IOrder{/// <summary>/// 向Order表插入数据/// </summary>/// <returns>成功:true,失败:false</returns>public bool Insert(){return true;}/// <summary>/// 修改Order表数据/// </summary>/// <param name="model">表数据对应实体</param>/// <returns>成功:true,失败:false</returns>public bool Update(OrderModel model){return true;}/// <summary>/// 删除Order表指定ID的记录/// </summary>/// <param name="id">表ID</param>/// <returns>成功:true,失败:false</returns>public bool Delete(int id){return true;}}
}

View Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mode;
using IDal;namespace DaL
{public class OrderDAL : IOrder{/// <summary>/// 向Order表插入数据/// </summary>/// <returns>成功:true,失败:false</returns>public bool Insert(){return true;}/// <summary>/// 修改Order表数据/// </summary>/// <param name="model">表数据对应实体</param>/// <returns>成功:true,失败:false</returns>public bool Update(OrderModel model){return true;}/// <summary>/// 删除Order表指定ID的记录/// </summary>/// <param name="id">表ID</param>/// <returns>成功:true,失败:false</returns>public bool Delete(int id){return true;}}
}

View Code

现在我们队BLL层OrderBLL做相应的改动,把数据访问实体orderDAL的类型,定义为接口IOrder类型,如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DaL;
using Mode;
using IDal;namespace Bll
{public class OrderBLL{protected IOrder orderDal;public OrderBLL(){ //在这里需要实力化orderDal
        }public bool Insert(OrderModel model){//业务点1//业务点2return orderDal.Insert();}/// <summary>/// 修改Order表数据/// </summary>/// <param name="model">表数据对应实体</param>/// <returns>成功:true,失败:false</returns>public bool Update(OrderModel model){//业务点1//业务点2return orderDal.Update(model);}/// <summary>/// 删除Order表指定ID的记录/// </summary>/// <param name="id">表ID</param>/// <returns>成功:true,失败:false</returns>public bool Delete(int id){//业务点1//业务点2return orderDal.Delete(id);}}
}

View Code

好了,现在让我们把目光聚集OrderBLL的构造函数。我们知道,OrderBLL会调用orderDAL去操作数据库,而orderDAL的类型为IOrder,也就是说但凡实现了IOrder接口的类实例都可以赋值给orderDAL。但是现在问题的关键是我们如何为orderDAL赋值,前面我们说过BLL移除了DAL的引用,所以在BLL层中直接去new数据访问层的实例,是不可能的。这里我提供两种处理方式,第一种采用IOC容器如spring.net帮助我们创建DAL层实例然后在OrderBLL的构造函数中赋值给orderDAL,另一种则是利用工厂模式和反射来创建DAL层实例了,本文将详述第二种,至于第一种在后面的系列中会有专门的章节讲述。现在我们在项目中添加一个Factoy工厂类库,并让BLL层引用Factoy类库,如图:

接着我们来写工厂类。我们从配置文件中读出程序集路径和类的全名,利用反射的原理创建DAL层的实例,代码如下

using IDal;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;namespace Factory
{public class OrderDALFactory{private static readonly string AssemblyName = ConfigurationManager.AppSettings["Assembly"];private static readonly string className = ConfigurationManager.AppSettings["className"];public static IOrder CreateOrder(){return (IOrder)Assembly.Load(AssemblyName).CreateInstance(className);}}
}

View Code

 
  最后我们在OrderBLL的构造函数利用OrderDALFactory工厂给orderDAL赋值

 public OrderBLL(){ //在这里需要实力化orderDalorderDal=OrderDALFactory.CreateOrder();}

这样我们就实现了BLL与DAL层的解耦,当我们BLL需要不同的IOrder实体的时候,我们只需要修改相应的配置文件即可。

总结

程序框架间层与层之间的解耦是富含挑战的一项工作,充分的体现出了面向对象的编程思想,巧妙的运用了各类设计模式。本文实现方法相对简单,仅当抛砖引玉。在接下来的文章中,我将就三层架构中各个层次的抽象与封装做详细说明。因为各个层次的抽象与封装是针对不同技术点来实现的,比如数据访问层,对EF技术与ADO.net技术的抽象与封装细节上就会有所不通。但总体思想是一致的,那就是我们必须为每个层次抽象出统一的接口,供上层引用,同时我们必须提供相应的注入方式,为调用层引用的接口实例赋值实例化。

转载于:https://www.cnblogs.com/shaoshun/p/3804474.html

企业级应用架构(一) 三层架构之解耦相关推荐

  1. 架构(三层架构)、框架(MVC)、设计模式三者异同点

    前言: 本博客主要针对架构.框架和设计模式三者的差别.还有三层和MVC的差别进行讨论.对于这三者一点都不了解的.请点在维基和百度百科上补补课.这里就不发链接了 软件架构(software archit ...

  2. java 三层架构_java三层架构详解

    三层架构模式介绍 三层架构模式: 三层架构(3-tier architecture) 通常意义上的三层架构就是将整个业务应用划分为:界面层(User Interface layer).业务逻辑层(Bu ...

  3. java ee 三层架构_JavaEE——三层架构模式介绍

    声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权:凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记. 三层架构模式介绍 三层架构模式: 三层架构(3-tier a ...

  4. [三层架构+WCF]三层架构+WCF实现TaskVision

    前面的一篇博文DebugLZQ使用三层架构实现了TaskVision,并在后面利用Webservice代替ClassLibrary实现SQL Server 2008数据库操作提供程序.关于三层架构的理 ...

  5. php的mvc三层架构,MVC三层架构

    1.三层架构 表现层(web层) web层:接受客户端请求,向客户端响应结果,通常客户端使用http协议请求: 控制层:负责接受请求 展示层:结果的展示 业务层(service层) 事务处理+业务处理 ...

  6. java 三层架构 mvc_java三层架构与mvc

    Java三层架构 - java独有 界面层(Web).业务逻辑(Service).数据访问层(Dao) WEB层: 包含JSP和Servlet等与WEB相关的内容 表示层属于最接近用户的一层,用于展示 ...

  7. 架构-三层架构:三层架构

    概述 顾名思义,三层架构分为三层,分别是"数据访问层"."业务逻辑层"."表示层". 数据访问层:数据访问层在作业过程中访问数据系统中的文件 ...

  8. 企业级应用架构(三)三层架构之数据访问层的改进以及测试DOM的发布

    在上一篇我们在宏观概要上对DAL层进行了封装与抽象.我们的目的主要有两个:第一,解除BLL层对DAL层的依赖,这一点我们通过定义接口做到了:第二,使我们的DAL层能够支持一切数据访问技术,如Ado.n ...

  9. 企业级应用架构(二)三层架构之数据访问层的封装与抽象

    在上一篇我们知道,要解除BLL对DAL的依赖,我们就必须抽象出DAL层的接口,同时基于DAL的数据访问技术很多,如EF,ADO.NET,LINQ TO SQL,因此,我们的数据访问层必须对这些技术提供 ...

最新文章

  1. 分布式服务框架原理与实践pdf_深度解析微服务治理的技术演进和架构实践
  2. mysql 查看运行级别_运行级别及进程
  3. springsecurity 认证之密码模式
  4. 未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序搜索
  5. python super()方法的作用_详解python的super()的作用和原理
  6. pip升级及关于pyecharts安装下载所遇到的问题及部分的解决
  7. 线性组合(linear combinations), 生成空间(span), 基向量(basis vectors)——线性代数本质(二)
  8. 牛客网——athletes 表包含运动员姓名,年纪和代表国家。下面哪个查询可以找出代表每个国家最年轻的运动员情况?
  9. 抢票软件之——py12306使用指南
  10. html嵌入播放器,flv视频播放器 Flvplayer.swf 可自动播放参数说明
  11. multiprocessing.pool详解
  12. 支付宝AR红包关闭,看昔日“网红”如何过气
  13. 自己动手搭建 Linux 0.12 编译环境 — Linux主机
  14. workbench设置单元坐标系_ansys workbench中新建坐标系的问题,求高人指点。
  15. 商业照明方案专用蓝牙芯片MS1656
  16. kubernetes容灾备份工具velero
  17. Hotmail Smtp邮箱发送的端口
  18. 字符串解码(猿辅导笔试题数箱子)
  19. Jupyter中运行.ipynb文件出现cannot import name ‘joblib‘ from ‘sklearn.externals‘
  20. 第二章 定义和构建索引(二)

热门文章

  1. android inset 标签,android – 有几个WindowInsets?
  2. VOC2007xml转YOLO的txt格式代码
  3. java 调用groovy_Java调用Groovy脚本
  4. IDEA编译运行Springboot+vue项目卡死,一直building和copying resources
  5. HTML+CSS+JS实现echarts图表炫光分布地图动画
  6. 基于java SSM springboot学生信息管理系统设计和实现2.0
  7. tcpsyn发生在哪层_必看面试题之计算机网络:来自一位拿到了腾讯和字节双offer的大佬...
  8. mysql with as 用法_Python之图解with语句
  9. 正则表达式的匹配规则
  10. acm用java怎么写_用java来写ACM