前言  

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

基础框架搭建

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

数据库访问层设计

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

 namespace Smp.Demo.EFDAL
{
public class BaseDal<T> where T : class,new()
{
SmpDBEntities m_dbContext = new SmpDBEntities(); // 条件查询
public virtual IQueryable<T> GetEntities(Expression<Func<T, bool>> whereLambda)
{
return m_dbContext.Set<T>().Where(whereLambda);
} // 分页查询
public virtual IQueryable<T> GetPageEntities<S>(int pageSize, int pageIndex, out int totalCount,
Func<T, bool> whereLambda, Func<T, S> orderLambda)
{
totalCount = m_dbContext.Set<T>().Count();
return m_dbContext.Set<T>().Where(whereLambda).
OrderBy(orderLambda).Skip((pageIndex - ) * pageSize).
Take(pageSize * pageIndex).AsQueryable();
} // 添加
public virtual T Add(T dbInfo)
{
m_dbContext.Set<T>().Add(dbInfo);
m_dbContext.SaveChanges();
return dbInfo;
} // 删除
public virtual bool Delete(T dbInfo)
{
m_dbContext.Entry<T>(dbInfo).State = System.Data.EntityState.Deleted;
return m_dbContext.SaveChanges() > ;
} // 修改
public virtual bool Update(T dbInfo)
{
m_dbContext.Entry(dbInfo).State = System.Data.EntityState.Modified;
return m_dbContext.SaveChanges() > ;
}
}
}

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

 namespace Smp.Demo.EFDAL
{
public class T_UserInfoDAL : BaseDal<T_UserInfo>
{ }
} namespace Smp.Demo.EFDAL
{
public class T_OrderInfoDAL : BaseDal<T_OrderInfo>
{ }
}

业务逻辑层设计

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

 namespace Smp.Demo.BLL
{
public class T_UserInfoBLL
{
T_UserInfoDAL m_userInfoDAL = new T_UserInfoDAL(); // 获取全部用户信息
public List<T_UserInfo> GetAllUserInfo()
{
return m_userInfoDAL.GetEntities(userInfo => true).ToList();
} // 添加用户并返回新增用户ID
public int AddUser(T_UserInfo userInfo)
{
var l_newUserInfo = m_userInfoDAL.Add(userInfo);
return l_newUserInfo.ID;
} // 删除指定用户
public bool Delete(T_UserInfo userInfo)
{
return m_userInfoDAL.Delete(userInfo);
}
}
}

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

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

思考

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

数据访问驱动层接口设计

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

 namespace Smp.Demo.IDAL
{
public interface IBaseDAL<T> where T : class ,new()
{
// 条件查询
IQueryable<T> GetEntities(Expression<Func<T, bool>> whereLambda); // 条件分页查询
IQueryable<T> GetPageEntities<S>(int pageSize, int pageIndex, out int totalCount,
Func<T, bool> whereLambda, Func<T, S> orderLambda); // 添加
T Add(T dbInfo); // 删除
bool Delete(T dbInfo); // 更新
bool Update(T dbInfo);
}
}

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

 namespace Smp.Demo.IDAL
{
public interface IUserInfo : IBaseDAL<T_UserInfo>
{
}
} namespace Smp.Demo.IDAL
{
public interface IOrderInfo : IBaseDAL<T_OrderInfo>
{
}
}

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

 namespace Smp.Demo.EFDAL
{
public class T_OrderInfoDAL : BaseDal<T_OrderInfo>,IOrderInfo
{ }
} namespace Smp.Demo.EFDAL
{
public class T_UserInfoDAL : BaseDal<T_UserInfo>,IUserInfo
{ }
}

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

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

抽象工厂模式的创建

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

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

 namespace Smp.Demo.DALFactory
{
public static class StaticDALFactory
{
public static IUserInfo GetUserInfoDAL()
{
string l_strAssemblyName = System.Configuration.ConfigurationManager.AppSettings["AssemblyName"];
return Assembly.Load(l_strAssemblyName).CreateInstance(l_strAssemblyName + ".T_UserinfoDAL") as IUserInfo;
} public static IOrderInfo GetOrderInfoDAL()
{
string l_strAssemblyName = System.Configuration.ConfigurationManager.AppSettings["AssemblyName"];
return Assembly.Load(l_strAssemblyName).CreateInstance(l_strAssemblyName + ".T_Orderinfo") as IOrderInfo;
}
}
}

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

 namespace Smp.Demo.BLL
{
public class T_UserInfoBLL
{
IUserInfo m_userInfoDAL = StaticDALFactory.GetUserInfoDAL(); // 获取全部用户信息
public List<T_UserInfo> GetAllUserInfo()
{
return m_userInfoDAL.GetEntities(userInfo => true).ToList();
} // 添加用户并返回新增用户ID
public int AddUser(T_UserInfo userInfo)
{
var l_newUserInfo = m_userInfoDAL.Add(userInfo);
return l_newUserInfo.ID;
} // 删除指定用户
public bool Delete(T_UserInfo userInfo)
{
return m_userInfoDAL.Delete(userInfo);
}
}
}

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

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

 namespace Smp.Demo.UI.Controllers
{
public class DemoController : Controller
{
//
// GET: /Demo/
public ActionResult Index()
{
var Users = new T_UserInfoBLL().GetAllUserInfo();
ViewData["users"] = Users;
return View();
}
}
} @{
Layout = null;
} <!DOCTYPE html> <html>
<head>
<title>Index</title>
</head>
<body>
<div>
@foreach (var item in ViewData["users"] as List<Smp.Demo.Model.T_UserInfo>)
{
<p>
@item.UserName
</p>
}
</div>
</body>
</html>

最后效果

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

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

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

  1. Java编码思想之什么是高内聚低耦合?

    分别描述的是模块内部特征,和模块外部引用关系. 内聚就是一个模块内各个元素彼此结合的紧密程度,高内聚就是一个模块内各个元素彼此结合的紧密程度高. 内聚是就其中任何一个模块的内部特征而言的. 耦合是就多 ...

  2. 面系那个对象开发原则.高内聚.低耦合+Python安装详细教程+print输出带颜色的方法

    面系那个对象开发原则.高内聚.低耦合 软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准.划分摸块的一个准则就是高内聚低耦合. 这是软件工程中的概念,是判断设计好坏的标准,主要是面向OO的设计, ...

  3. C# 低耦合 高内聚

    低耦合 loosely Coupling 松散的耦合关系=炮友 couple=夫妻 夫妻=法律约束.家庭.生活.财产.繁衍 炮友:吃喝玩乐,不会产生感情方面的依赖       内聚性 内聚性又称块内联 ...

  4. 如何理解低耦合AND高内聚?[转]

    1.高内聚 首先我们来看看内聚的含义:软件含义上的内聚其实是从化学中的分子的内聚演变过来的,化学中的分子间的作用力,作用力强则表现为内聚程度高.在软件中内聚程度的高低,标识着软件设计的好坏. 我们在进 ...

  5. Office之什么是高内聚低耦合

    ---恢复内容开始--- 高内聚低耦合,是软件工程中的概念,是判断设计好坏的标准,主要是面向对象的设计,主要是看类的内聚性是否高,耦合度是否低. 粗劣的说就指的是:单独模块间有着强大的凝聚力,不同的模 ...

  6. Java学习之浅析高内聚低耦合

    •前言 如果你涉及软件开发,可能会经常听到 "高内聚,低耦合" 这种概念型词语. 可是,何为 "高内聚,低耦合" 呢? •概念 "高内聚,低耦合&qu ...

  7. abp加DDD开发:低耦合、可复用、可扩展的【工单】业务模块-简介和集成

    前言 很多场景[单体+模块化]比微服务更合适,开发难度低.代码可复用性强.可扩展性强.模块化开发有些难点,模块启动与卸载.模块之间的依赖和通讯.asp.net core abp为我们提供了模块化开发能 ...

  8. nginx内置高可用配置与第三方高可用模块nginx_ustream_check_mudule配置

    1. nginx 第三方高可用模块 IP 备注 10.0.0.63 proxy 10.0.0.64 web1 10.0.0.65 web2 这里会讲解一些nignx常用高可用方案,以及引入第三方高可用 ...

  9. 面向UI编程:ui.js 1.1 使用观察者模式完成组件之间数据流转,彻底分离组件之间的耦合,完成组件的高内聚

    开头想明确一些概念,因为有些概念不明确会导致很多问题,比如你写这个框架为什么不去解决啥啥啥的问题,哎,心累. 什么是框架? 百度的解释:框架(Framework)是整个或部分系统的可重用设计,表现为一 ...

随机推荐

  1. 内置的re模块

    re(正则表达式) 字符匹配: 普通字符匹配:re.findall("alex","shfalexjaf"),直接查找符合的字符 元字符:  .  ^ $ * ...

  2. du df的用法

    1,两者区别 du,disk usage,是通过搜索文件来计算每个文件的大小然后累加,du能看到的文件只是一些当前存在 的,没有被删除的.他计算的大小就是当前他认为存在的所有文件大小的累加和. df, ...

  3. git push -u origin master和git push <远程主机名> <本地分支名>:<远程分支名>作用

    git push git push命令用于将本地分支的更新,推送到远程主机.它的格式与git pull命令相仿. $ git push <远程主机名> <本地分支名>:< ...

  4. nginx图片过滤处理模块http_image_filter_module

    nginx图片过滤处理模块http_image_filter_module安装配置笔记 http_image_filter_module是nginx提供的集成图片处理模块,支持nginx-0.7.54 ...

  5. Python中decode与encode的区别

    摘抄: 字符串在Python内部的表示是Unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符解码(decode)成unicode,再从unicode编码 ...

  6. 五年双十一:SLS数据管道发展之路

    日志服务SLS是一款飞天团队自研产品,服务云上云下3W+客户,并在阿里经济体中作为日志数据的基础设施,在过去几年中经历多次双十一.双十二.新春红包锤炼.在2019双十一中: 服务阿里经济体3W+ 应用 ...

  7. Bugku 杂项 宽带信息泄露

    宽带信息泄露 flag是宽带用户名 下载文件后用RouterPassView打开,搜索username即可

  8. 超大文件上传方案(PHP)

    前段时间做视频上传业务,通过网页上传视频到服务器. 视频大小 小则几十M,大则 1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题:1,文件过大,超出服务端的请求大小限制:2,请求时间过长, ...

  9. codevs 3137-3139 栈练习 x

    3中 换行需谨慎!!!一定要注意换行!!! 3137 栈练习1  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold     题目描述 Description 给定一 ...

  10. HTML To Word

    一.源码特点       1.在一些实际的应用场景中,有用户需要将一批规范的资料网页保存为WORD文档以便离线传阅或用于其它需求.在此之前,使用了OFFICE组件来尝试完成此功能需求,但是效果都不尽如 ...