模块内高内聚?模块间低耦合?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

原文地址:https://www.cnblogs.com/insipid/p/11116844.html

时间: 2024-10-09 06:52:47

模块内高内聚?模块间低耦合?MVC+EF演示给你看!的相关文章

面向对象编程、模块内高内聚、模块间低耦合、数据库操作工具类

一.web.config帮助类(ConfigHelper.cs) 1 using System; 2 using System.Collections.Generic; 3 using System.Configuration; 4 using System.Reflection; 5 6 namespace Common 7 { 8 /// <summary> 9 /// web.config操作类 10 /// author:陈彦斌 11 /// 时间:2019年7月14日23:32:08

《如何在struts+spring+hibernate的框架下构建低耦合高内聚的软件》

问题的提出我常常在思考一个问题,我们如何能设计出高水平.高质量的软件出来.怎样是高水平.高质量的软件?它应当是易于维护.易于适应变更.可重用性好的一个系统.如何做到这一点呢?答案当然是"低耦合.高内聚"了.低耦合就是软件在构造的时候,各个模块.各个功能.各个类都不会过度依赖于它周围的环境.只有这样,才能使我们的模块(功能.类)在周围发生变更时不受影响,做到易于维护和易于适应变更.正因为如此,也使它更易于重用到其它功能类似的环境中,提高了重用性.高内聚则使软件中的各个模块(功能.类)能够

对高内聚,低耦合的理解

内聚:一个模块内各个元素彼此结合的紧密程度 耦合:一个软件结构内不同模块之间互连程度的度量 最近编码的时候,总是在犹豫是把某个方法封装在一个类里,还是单独的封装成一个类.这让我突然想起内聚耦合这两个名词. 我们一直追求着,高内聚,低耦合. 对于低耦合,我粗浅的理解是:一个完整的系统,模块与模块之间,尽可能的使其独立存在. 也就是说,让每个模块,尽可能的独立完成某个特定的子功能. 模块与模块之间的接口,尽量的少而简单. 如果某两个模块间的关系比较复杂的话,最好首先考虑进一步的模块划分. 这样有利于

什么是高内聚、低耦合?

起因:模块独立性指每个模块只完成系统要求的独立子功能,并且与其他模块的联系最少且接口简单,两个定性的度量标准――耦合性和内聚性. 内聚:一个模块内各个元素彼此结合的紧密程度 耦合:一个软件结构内不同模块之间互连程度的度量 耦合性也称块间联系.指软件系统结构中各模块间相互联系紧密程度的一种度量.模块之间联系越紧密,其耦合性就越强,模块的独立性则越差.模块间耦合高低取决于模块间接口的复杂性.调用的方式及传递的信息. 耦合性分类(低――高): 无直接耦合;数据耦合;标记耦合;控制耦合;公共耦合;内容耦

高内聚低耦合简单学习

起因:模块独立性指每个模块只完成系统要求的独立子功能,并且与其他模块的联系最少且接口简单, 两个定性的度量标准――耦合性和内聚性. 耦合性也称块间联系.指软件系统结构中各模块间相互联系紧密程度的一种度量.模块之间联系越 紧密,其耦合性就越强,模块的独立性则越差.模块间耦合高低取决于模块间接口的复杂性.调用的方 式及传递的信息.   耦合性分类(低――高): 无直接耦合;数据耦合;标记耦合;控制耦合;公共耦合;内容耦合; 1 无直接耦合: 2 数据耦合: 指两个模块之间有调用关系,传递的是简单的数

小菜学设计模式——高内聚、低耦合

背景 本文标题为什么叫小菜学习设计模式,原因是本文内容主要是学习<大话设计模式>时的笔记摘要部分,当然,并不是记录书中小菜的学习过程,这个完全没有意义,而是指本人学习设计模式的成长之旅. 真诚的希望自己能够从一名小菜成长为一名大鸟! 编写的程序应该满足: 1)可维护 2)可扩展 3)可复用 4)够灵活 废话少说,言归正传,设计模式原则之:高内聚.低耦合 当然,这条原则不是面向接口编程的具体原则,他是所有原则.所有设计模式都必须遵循的一条亘古不变的宗旨. 网上学习与记录 起因:模块独立性指每个模

什么是高内聚,低耦合?

概念: 高内聚是指一个软件模块是由相关性很强的代码组成,只负责一项任务,也就是常说的单一责任原则. 低耦合是:一个完整的系统,模块与模块之间,尽可能的使其独立存在. 内聚性又称块内联系.指模块的功能强度的度量,即一个模块内部各个元素彼此结合的紧密程度的度量.若一个模块内各元素(语名之间.程序段之间)联系的越紧密,则它的内聚性就越高. 内聚性匪类(低――高): 偶然内聚;逻辑内聚;时间内聚;通信内聚;顺序内聚;功能内聚; 1 偶然内聚: 指一个模块内的各处理元素之间没有任何联系. 2 逻辑内聚:

浅谈面向对象开发原则:高内聚,低耦合

软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准.划分摸块的一个准则就是高内聚低耦合. 这是软件工程中的概念,是判断设计好坏的标准,主要是面向OO的设计,主要是看类的内聚性是否高,偶合度是否低. 每一个类完成特定的独立的功能,这个就是高内聚.耦合就是类之间的互相调用关系,如果耦合很强,互相牵扯调用很多,那么会牵一发而动全身,不利于维护和扩展. 类之间的设置应该要低耦合,但是每个类应该要高内聚.耦合是类之间相互依赖的尺度.如果每个对象都有引用其它所有的对象,那么就有高耦合,这是不合乎要求的

C# 低耦合 高内聚

低耦合 loosely Coupling 松散的耦合关系=炮友 couple=夫妻 夫妻=法律约束.家庭.生活.财产.繁衍 炮友:吃喝玩乐,不会产生感情方面的依赖 内聚性 内聚性又称块内联系.指模块的功能强度的度量,即一个模块内部各个元素彼此结合的紧密程度的度量.若一个模块内各元素(语名之间.程序段之间)联系的越紧密,则它的内聚性就越高. 内聚性匪类(低――高): 偶然内聚;逻辑内聚;时间内聚;通信内聚;顺序内聚;功能内聚; 1 偶然内聚: 指一个模块内的各处理元素之间没有任何联系. 2 逻辑内