zoukankan      html  css  js  c++  java
  • 模块内高内聚?模块间低耦合?MVC+EF演示给你看!

    前言  

      在软件项目开发过程中,我们总能听见“高内聚,低耦合”,即使这种思想在我们学习编程的过程中就已经耳濡目染。可一旦当我们上项目,赶进度的时候我们就会“偷懒”,能省时间就省。管他什么设计模式,什么软件架构先实现上线再说。当然,如果这是一个一次性项目,或者是一个比较简单的项目还好说,但如果这个项目牵扯到后期的维护再开发,那么之前的“偷懒”就会成为“技术债”。最近刚研究完EF框架,写个demo练练手,正好贴出来做个抛砖引玉的作用。希望大家一起讨论,共同进步!

    基础框架搭建

      基础架构也就是常用的三层架构,UI层:MVC,数据库访问驱动层:Entity Framework,由于是演示在这里我们的Model层就用两个表做演示了(T_UserInfo,T_OrderInfo)

     数据库访问层设计

      在基础框架搭建完毕后,我们再设计一下数据库访问驱动层DAL。首先我们抽象一个BaseDAL,写一个公共的CRUD。

     1 namespace Smp.Demo.EFDAL
     2 {
     3     public class BaseDal<T> where T : class,new()
     4     {
     5         SmpDBEntities m_dbContext = new SmpDBEntities();
     6 
     7         // 条件查询
     8         public virtual IQueryable<T> GetEntities(Expression<Func<T, bool>> whereLambda)
     9         {
    10             return m_dbContext.Set<T>().Where(whereLambda);
    11         }
    12 
    13         // 分页查询
    14         public virtual IQueryable<T> GetPageEntities<S>(int pageSize, int pageIndex, out int totalCount,
    15             Func<T, bool> whereLambda, Func<T, S> orderLambda)
    16         {
    17             totalCount = m_dbContext.Set<T>().Count();
    18             return m_dbContext.Set<T>().Where(whereLambda).
    19                    OrderBy(orderLambda).Skip((pageIndex - 1) * pageSize).
    20                    Take(pageSize * pageIndex).AsQueryable();
    21         }
    22 
    23         // 添加
    24         public virtual T Add(T dbInfo)
    25         {
    26             m_dbContext.Set<T>().Add(dbInfo);
    27             m_dbContext.SaveChanges();
    28             return dbInfo;
    29         }
    30 
    31         // 删除
    32         public virtual bool Delete(T dbInfo)
    33         {
    34             m_dbContext.Entry<T>(dbInfo).State = System.Data.EntityState.Deleted;
    35             return m_dbContext.SaveChanges() > 0;
    36         }
    37 
    38         // 修改
    39         public virtual bool Update(T dbInfo)
    40         {
    41             m_dbContext.Entry(dbInfo).State = System.Data.EntityState.Modified;
    42             return m_dbContext.SaveChanges() > 0;
    43         }
    44     }
    45 }

     然后我们封装T_UserInfo和T_OrderInfo的数据库访问层,直接继承BaseDAL即可,继承后子类中有特殊需求单独实现即可。

     1 namespace Smp.Demo.EFDAL
     2 {
     3     public class T_UserInfoDAL : BaseDal<T_UserInfo>
     4     {
     5         
     6     }
     7 }
     8 
     9 namespace Smp.Demo.EFDAL
    10 {
    11     public class T_OrderInfoDAL : BaseDal<T_OrderInfo>
    12     {
    13 
    14     }
    15 }

     业务逻辑层设计 

      业务逻辑层在三层架构中权重是比较高的一层,该层在项目中起到一个承上启下的作用,既要操作数据访问层的CRUD,也要处理UI层的业务逻辑。那么接下来我们就以T_UserInfo来写一个业务逻辑层的演示Demo

     1 namespace Smp.Demo.BLL
     2 {
     3     public class T_UserInfoBLL
     4     {
     5         T_UserInfoDAL m_userInfoDAL = new T_UserInfoDAL();
     6 
     7         // 获取全部用户信息
     8         public List<T_UserInfo> GetAllUserInfo()
     9         {
    10             return m_userInfoDAL.GetEntities(userInfo => true).ToList();
    11         }
    12 
    13         // 添加用户并返回新增用户ID
    14         public int AddUser(T_UserInfo userInfo)
    15         {
    16             var l_newUserInfo = m_userInfoDAL.Add(userInfo);
    17             return l_newUserInfo.ID;
    18         }
    19 
    20         // 删除指定用户
    21         public bool Delete(T_UserInfo userInfo)
    22         {
    23             return m_userInfoDAL.Delete(userInfo);
    24         }
    25     }
    26 }

    当我们DAL层和BLL层的框架写完后,我们在当前项目中创建一个测试单元,测试以上框架是否能够正常运行

     经测试,就目前而言我们搭建的架构是可以正常运行的,那么我们来看一下当前DAL层和BLL层之间的UML图

     思考

      通过以上的UML图和代码我们可以看到,每个模块都相对独立,基本上完成了“高内聚”的思想。但唯一不足的就是BLL层和DAL之间的连接总是不那么尽如人意。例如存在这样的需求,当用户量大了以后DAL层想从EF框架换为NH框架,或者是想将数据库从SqlServer换为Oracle。那么我们以上的设计是不符合“低耦合”思想的,因为BLL层和DAL层的依赖是那么的强,一旦数据库访问驱动层更换那么BLL层和DAL层的改动是非常多的。怎么办呢?我想大家在开发过程中可能听过这么一句话“面向接口编程”。那么我们也来对BLL层和DAL层之间面向接口编程吧!

    数据访问驱动层接口设计

      首先,在当前项目中新增一个“IDAL”接口项目。然后我们对DAL层的CRUD来进行一个抽象。

     1 namespace Smp.Demo.IDAL
     2 {
     3     public interface IBaseDAL<T> where T : class ,new()
     4     {
     5         // 条件查询
     6         IQueryable<T> GetEntities(Expression<Func<T, bool>> whereLambda);
     7 
     8         // 条件分页查询
     9         IQueryable<T> GetPageEntities<S>(int pageSize, int pageIndex, out int totalCount,
    10            Func<T, bool> whereLambda, Func<T, S> orderLambda);
    11 
    12         // 添加
    13         T Add(T dbInfo);
    14 
    15         // 删除
    16         bool Delete(T dbInfo);
    17 
    18         // 更新
    19         bool Update(T dbInfo);
    20     }
    21 }

    其次我们再继承“IDAL”写IUserInfo和IOrderInfo数据库访问驱动层接口

     1 namespace Smp.Demo.IDAL
     2 {
     3     public interface IUserInfo : IBaseDAL<T_UserInfo>
     4     {
     5     }
     6 }
     7 
     8 namespace Smp.Demo.IDAL
     9 {
    10     public interface IOrderInfo : IBaseDAL<T_OrderInfo>
    11     {
    12     }
    13 }

     然后我们再将EFDAL层中的T_OrderInfoDAL和T_UserInfoDAL再分别继承IUserInfo和IOrderInfo

     1 namespace Smp.Demo.EFDAL
     2 {
     3     public class T_OrderInfoDAL : BaseDal<T_OrderInfo>,IOrderInfo
     4     {
     5 
     6     }
     7 }
     8 
     9 namespace Smp.Demo.EFDAL
    10 {
    11     public class T_UserInfoDAL : BaseDal<T_UserInfo>,IUserInfo
    12     {
    13         
    14     }
    15 }

     重新设计后UML图是这样的,也就是在BLL层和DAL层之间加了个中间层,方便后期动态配置数据访问驱动层。降低耦合程度

     当我们将接口设计好后,我们再在当前项目下创建一个DALFactory抽象工厂项目,用于后期基于Web.config文件动态获取DAL层访问

    抽象工厂模式的创建

      第一步、打开UI层在Web.confg文件中找到appSettings节点中添加后期动态创建的DAL层程序集节点名称方便后期反射指定程序集

      第二步、创建一个新建项目DALFactory抽象工厂,用户按照Web.config动态创建指定DAL数据库访问驱动

     1 namespace Smp.Demo.DALFactory
     2 {
     3     public static class StaticDALFactory
     4     {
     5         public static IUserInfo GetUserInfoDAL()
     6         {
     7             string l_strAssemblyName = System.Configuration.ConfigurationManager.AppSettings["AssemblyName"];
     8             return Assembly.Load(l_strAssemblyName).CreateInstance(l_strAssemblyName + ".T_UserinfoDAL") as IUserInfo;
     9         }
    10 
    11         public static IOrderInfo GetOrderInfoDAL()
    12         {
    13             string l_strAssemblyName = System.Configuration.ConfigurationManager.AppSettings["AssemblyName"];
    14             return Assembly.Load(l_strAssemblyName).CreateInstance(l_strAssemblyName + ".T_Orderinfo") as IOrderInfo;
    15         }
    16     }
    17 }

      第三步、修改BLL层中访问DAL层的访问方式

     1 namespace Smp.Demo.BLL
     2 {
     3     public class T_UserInfoBLL
     4     {
     5         IUserInfo m_userInfoDAL = StaticDALFactory.GetUserInfoDAL();
     6 
     7         // 获取全部用户信息
     8         public List<T_UserInfo> GetAllUserInfo()
     9         {
    10             return m_userInfoDAL.GetEntities(userInfo => true).ToList();
    11         }
    12 
    13         // 添加用户并返回新增用户ID
    14         public int AddUser(T_UserInfo userInfo)
    15         {
    16             var l_newUserInfo = m_userInfoDAL.Add(userInfo);
    17             return l_newUserInfo.ID;
    18         }
    19 
    20         // 删除指定用户
    21         public bool Delete(T_UserInfo userInfo)
    22         {
    23             return m_userInfoDAL.Delete(userInfo);
    24         }
    25     }
    26 }

      第四步、将EFDAL中app.config的连接字符串配置到UI层web.config中

      第五步、在UI层中创建一个demo控制器,并同时创建一个Index视图

     1 namespace Smp.Demo.UI.Controllers
     2 {
     3     public class DemoController : Controller
     4     {
     5         //
     6         // GET: /Demo/
     7         public ActionResult Index()
     8         {
     9             var Users = new T_UserInfoBLL().GetAllUserInfo();
    10             ViewData["users"] = Users;
    11             return View();
    12         }
    13     }
    14 }
    15 
    16 @{
    17     Layout = null;
    18 }
    19 
    20 <!DOCTYPE html>
    21 
    22 <html>
    23 <head>
    24     <title>Index</title>
    25 </head>
    26 <body>
    27     <div>
    28         @foreach (var item in ViewData["users"] as List<Smp.Demo.Model.T_UserInfo>)
    29         {
    30             <p>
    31                 @item.UserName
    32             </p>
    33         }
    34     </div>
    35 </body>
    36 </html>

    最后效果

     这样的话后期我们就可以很方便的扩展数据访问层啦!

    源码下载地址:https://github.com/p9966/Smp.Demo

  • 相关阅读:
    CDH6.3.1安装详细步骤(感写B站若泽大数据)
    windows远程ubuntu UI教程
    CentOS7搭建Tensorflow计算环境(cuda+cudnn+jupyterlab(Anaconda3)+pytorch+Tensorflow)
    中国计算机学会推荐国际学术会议和期刊目录-2019
    基于BA网络模型的二部图数据集生成
    GitHub文件的克隆与上传
    博客园中随笔,文章的区别
    Pycharm新建文件时头部模板的配置方法
    asyncio 和aiohttp
    随机UA
  • 原文地址:https://www.cnblogs.com/insipid/p/11116844.html
Copyright © 2011-2022 走看看