企业级应用架构(一) 三层架构之解耦
前言
前段時(shí)間朋友拿了個(gè)網(wǎng)站給我,讓我?guī)兔μ砑訋讉€(gè)小功能,我爽快的答應(yīng)了,但是當(dāng)我打開源碼,我瞬間就奔潰了,整個(gè)項(xiàng)目連最基本的三層框架也沒有搭建,僅僅是封裝了一個(gè)sqlhelp作為數(shù)據(jù)庫的操作接口,項(xiàng)目中的SQL查詢語句無處不在,業(yè)務(wù)邏輯緊緊耦合在UI邏輯中,看到這樣的代碼,坦白來說,我什么興致都沒有了,但是礙著人情,我硬著頭皮,把基本功能的完成交差,通過這件事情,我對(duì)軟件分層進(jìn)行了深入的思考。
三層架構(gòu)
說到三層架構(gòu),大伙都很熟悉,我也不再多啰嗦了,我們直接快速搭建一個(gè)。
???? 項(xiàng)目的引用關(guān)系是:StructWed->BLL,Model;BLL->DAL,Model;DAL->Model。下面我們來演示一下程序流程,假設(shè)我們的數(shù)據(jù)庫有一張訂單表Order表,我們的業(yè)務(wù)是針對(duì)Order表進(jìn)行的增刪改查,那么根據(jù)三層架構(gòu)的編程模式,我們就需要建立起對(duì)應(yīng)的Model層實(shí)體,數(shù)據(jù)訪問層實(shí)體和業(yè)務(wù)層實(shí)體,我們分別用OrderModel,OrderDAL,OrderBLL表示,代碼如下,由于僅僅是為了演示,所以我并未提供相應(yīng)的實(shí)現(xiàn)。
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表插入數(shù)據(jù)/// </summary>/// <returns>成功:true,失敗:false</returns>public bool Insert(){return true;}/// <summary>/// 修改Order表數(shù)據(jù)/// </summary>/// <param name="model">表數(shù)據(jù)對(duì)應(yīng)實(shí)體</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){//業(yè)務(wù)點(diǎn)1//業(yè)務(wù)點(diǎn)2return orderDal.Insert();}/// <summary>/// 修改Order表數(shù)據(jù)/// </summary>/// <param name="model">表數(shù)據(jù)對(duì)應(yīng)實(shí)體</param>/// <returns>成功:true,失敗:false</returns>public bool Update(OrderModel model){//業(yè)務(wù)點(diǎn)1//業(yè)務(wù)點(diǎn)2return orderDal.Update(model);}/// <summary>/// 刪除Order表指定ID的記錄/// </summary>/// <param name="id">表ID</param>/// <returns>成功:true,失敗:false</returns>public bool Delete(int id){//業(yè)務(wù)點(diǎn)1//業(yè)務(wù)點(diǎn)2return orderDal.Delete(id);}} } View Code好了,現(xiàn)在讓我們把目光聚焦到OrderBLL上面來。我們發(fā)現(xiàn)OrderBLL對(duì)數(shù)據(jù)庫Order表的所有操作都是在調(diào)用其內(nèi)部創(chuàng)建的orderDAL實(shí)體的同名方法,換句話來說OrderBLL指示其內(nèi)部orderDAL實(shí)體去完成數(shù)據(jù)庫的增刪改查。
好現(xiàn)在,我們思考一下。假設(shè)有一天我們發(fā)現(xiàn)我們數(shù)據(jù)訪問層的orderDAL實(shí)體代碼寫的很不優(yōu)雅,效率極差,我們想用一個(gè)更優(yōu)雅的實(shí)體,比如OrderActiveDAL去替換掉它,那么這個(gè)時(shí)候我們OrderBLL的代碼就必須做相應(yīng)的改動(dòng),如下
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){//業(yè)務(wù)點(diǎn)1//業(yè)務(wù)點(diǎn)2return orderActive.Insert();}/// <summary>/// 修改Order表數(shù)據(jù)/// </summary>/// <param name="model">表數(shù)據(jù)對(duì)應(yīng)實(shí)體</param>/// <returns>成功:true,失敗:false</returns>public bool Update(OrderModel model){//業(yè)務(wù)點(diǎn)1//業(yè)務(wù)點(diǎn)2return orderActive.Update(model);}/// <summary>/// 刪除Order表指定ID的記錄/// </summary>/// <param name="id">表ID</param>/// <returns>成功:true,失敗:false</returns>public bool Delete(int id){//業(yè)務(wù)點(diǎn)1//業(yè)務(wù)點(diǎn)2return orderActive.Delete(id);}} } View Code? ? 這顯然不是一種好的處理方式。我們追求的是在替換orderDal實(shí)體的同時(shí),不修改OrderBLL的任何代碼,換句話說就是解除BLL層與DAL層的耦合,為了達(dá)到這個(gè)目的,我們添加一個(gè)叫IDAL的接口類庫,如圖
????? 特別注意,我們?cè)贐LL層中添加了對(duì)IDA的引用,同時(shí)移除了對(duì)DAL的引用,這就意味著我們?cè)贐LL中無法創(chuàng)建(new)DAL層中的任何實(shí)體。下面我們?cè)贗DA項(xiàng)目中定義IOrder接口,如下
using Mode; using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace IDal {public interface IOrder{/// <summary>/// 向Order表插入數(shù)據(jù)/// </summary>/// <returns>成功:true,失敗:false</returns>bool Insert();/// <summary>/// 修改Order表數(shù)據(jù)/// </summary>/// <param name="model">表數(shù)據(jù)對(duì)應(yīng)實(shí)體</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,同時(shí)讓OrderActiveDAL,OrderDal分別實(shí)現(xiàn)IOrder接口,如下
using IDal; using Mode; using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace DaL {class OrderActiveDAL : IOrder{/// <summary>/// 向Order表插入數(shù)據(jù)/// </summary>/// <returns>成功:true,失敗:false</returns>public bool Insert(){return true;}/// <summary>/// 修改Order表數(shù)據(jù)/// </summary>/// <param name="model">表數(shù)據(jù)對(duì)應(yīng)實(shí)體</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表插入數(shù)據(jù)/// </summary>/// <returns>成功:true,失敗:false</returns>public bool Insert(){return true;}/// <summary>/// 修改Order表數(shù)據(jù)/// </summary>/// <param name="model">表數(shù)據(jù)對(duì)應(yīng)實(shí)體</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??? 現(xiàn)在我們隊(duì)BLL層OrderBLL做相應(yīng)的改動(dòng),把數(shù)據(jù)訪問實(shí)體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(){ //在這里需要實(shí)力化orderDal }public bool Insert(OrderModel model){//業(yè)務(wù)點(diǎn)1//業(yè)務(wù)點(diǎn)2return orderDal.Insert();}/// <summary>/// 修改Order表數(shù)據(jù)/// </summary>/// <param name="model">表數(shù)據(jù)對(duì)應(yīng)實(shí)體</param>/// <returns>成功:true,失敗:false</returns>public bool Update(OrderModel model){//業(yè)務(wù)點(diǎn)1//業(yè)務(wù)點(diǎn)2return orderDal.Update(model);}/// <summary>/// 刪除Order表指定ID的記錄/// </summary>/// <param name="id">表ID</param>/// <returns>成功:true,失敗:false</returns>public bool Delete(int id){//業(yè)務(wù)點(diǎn)1//業(yè)務(wù)點(diǎn)2return orderDal.Delete(id);}} } View Code?? 好了,現(xiàn)在讓我們把目光聚集OrderBLL的構(gòu)造函數(shù)。我們知道,OrderBLL會(huì)調(diào)用orderDAL去操作數(shù)據(jù)庫,而orderDAL的類型為IOrder,也就是說但凡實(shí)現(xiàn)了IOrder接口的類實(shí)例都可以賦值給orderDAL。但是現(xiàn)在問題的關(guān)鍵是我們?nèi)绾螢閛rderDAL賦值,前面我們說過BLL移除了DAL的引用,所以在BLL層中直接去new數(shù)據(jù)訪問層的實(shí)例,是不可能的。這里我提供兩種處理方式,第一種采用IOC容器如spring.net幫助我們創(chuàng)建DAL層實(shí)例然后在OrderBLL的構(gòu)造函數(shù)中賦值給orderDAL,另一種則是利用工廠模式和反射來創(chuàng)建DAL層實(shí)例了,本文將詳述第二種,至于第一種在后面的系列中會(huì)有專門的章節(jié)講述。現(xiàn)在我們?cè)陧?xiàng)目中添加一個(gè)Factoy工廠類庫,并讓BLL層引用Factoy類庫,如圖:
?
???接著我們來寫工廠類。我們從配置文件中讀出程序集路徑和類的全名,利用反射的原理創(chuàng)建DAL層的實(shí)例,代碼如下
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?
? 最后我們?cè)贠rderBLL的構(gòu)造函數(shù)利用OrderDALFactory工廠給orderDAL賦值
??這樣我們就實(shí)現(xiàn)了BLL與DAL層的解耦,當(dāng)我們BLL需要不同的IOrder實(shí)體的時(shí)候,我們只需要修改相應(yīng)的配置文件即可。
總結(jié)??
? 程序框架間層與層之間的解耦是富含挑戰(zhàn)的一項(xiàng)工作,充分的體現(xiàn)出了面向?qū)ο蟮木幊趟枷?#xff0c;巧妙的運(yùn)用了各類設(shè)計(jì)模式。本文實(shí)現(xiàn)方法相對(duì)簡單,僅當(dāng)拋磚引玉。在接下來的文章中,我將就三層架構(gòu)中各個(gè)層次的抽象與封裝做詳細(xì)說明。因?yàn)楦鱾€(gè)層次的抽象與封裝是針對(duì)不同技術(shù)點(diǎn)來實(shí)現(xiàn)的,比如數(shù)據(jù)訪問層,對(duì)EF技術(shù)與ADO.net技術(shù)的抽象與封裝細(xì)節(jié)上就會(huì)有所不通。但總體思想是一致的,那就是我們必須為每個(gè)層次抽象出統(tǒng)一的接口,供上層引用,同時(shí)我們必須提供相應(yīng)的注入方式,為調(diào)用層引用的接口實(shí)例賦值實(shí)例化。
?
轉(zhuǎn)載于:https://www.cnblogs.com/shaoshun/p/3804474.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的企业级应用架构(一) 三层架构之解耦的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cannot be resolved o
- 下一篇: HappyLeetcode64:Sqrt