MVC 多層架構1

多層架構是什麼?

多層架構是開發人員在開發過程中面對複雜且易變的需求採起的一種以隔離控制爲主的應對策略,關於多層架構的標準,我認爲有一句話是比較有表明性的「每一層均可以單獨部署」,最傳統,最簡單的就是從三層開始的:html

將整個項目自下而上的分爲:數據持久(數據訪問)層,邏輯(業務)層,UI(展示)層。前端

數據訪問層:負責將數據持久化響應的數據存儲設備上,如DataBase,Txt,Excel等。服務器

業務邏輯層:負責處理爲知足軟件需求而訂製的一系列的邏輯與業務,如用戶在前端下訂單以後,整個業務流可能涉及到,獲取用戶信息,獲取商品信息,獲取購物車信息,驗證商品可購買數量是否知足本次購買,針對用戶身份產生不一樣的優惠策略,同時會驗證Cookie,Session等端產生數據的有效性,最終纔會產生訂單,而訂單產生以後會涉及到倉儲物流等一系列的Erp系統業務,全部的這一套都屬於「下訂單」這一需求的業務邏輯。架構

展現層:負責與用戶交互的界面,良好的用戶體驗可能是使用在這裏。併發

學習過Petshop的話,對於三層都不會陌生:框架

可是隨着業務的複雜每一層都會有本身的進化,最終有了無數附加在三層之上的框架與開發思想。分佈式

Mvc與MVP:

首先我一直認爲這兩種事屬於展示層的,「展示層MCV」,「展示層MVP」。工具

而後咱們站在展示層的角度思考一下「Mvc」與「MVP」。學習

Mvc:分爲model,Controller,View,相信你們對於他已經很熟悉了,在此再也不累述。ui

MVP:MVP有Model-Presenter-View三個層次

其實在樓主最開始接觸Mvc的時候,就在想若是直接經過Controller與Model交互是否是顯得有一些「不乾淨」,由於在樓主眼裏「展示層的Controller」,作得最多的應該就是對於請求路由的不一樣響應與調用,可是不少的例子會將一些數據驗證,去糟的操做過程放在Controller中,顯得不三不四。當MVP出現的時候,一切知足了樓主的幻想,P的過程就是知足了這一需求,P起到中介的做用,負責接收視圖請求,再把結果映射到view上,P能夠不對View作強引用,可經過IView適配多個view。固然我也會在這裏作一些針對於終端數據的驗證與過濾。

業務邏輯:

從描述上能夠看的很清楚,整個自上而下的結構,最複雜,最可能失控的就是業務邏輯層,由於其中包含着許多的不可控因素,每一個行業領域的需求都有可能包含自身的領域知識。因而在以後的多層架構發展構成當中,更多的變化與智慧是體如今這裏。

領域驅動:限於本人才學不能在這裏分享太多,以防誤導你們,想了解更多可參考園子裏的其餘大牛,其實沒有3,5年相關經驗是很難理解的,我的感受若是你不理解的話也不會對你有什麼影響,由於領域驅動是創建在良好的面相對象分析,邊界劃分基礎之上的,在學習的過程中已經能幫助你去學習到足夠多的知識了,最終到不到山巔其實已經無所謂了。

簡單的說,這個思想最重要的是以業務領域爲核心進行發散,指望在變動程序的其餘部分,不會影響到領域模型,也就是那句話爲了「複雜的系統應用程序中業務規則行爲方式(就是「領域邏輯」)是會常常變化的,咱們要去擁抱這種變化」。結構圖:

CQRS:是指命令查詢職責的分離,是一個小的模式形態,該模式的關鍵在於:「一個方法要麼是用來改變某個對象的狀態的,要麼就是返回一個結果,這二者不會同時並存」。將整個系統分拆爲兩個部分:

  • Commands(命令) - 改變某一個對象或整個系統的狀態(有時也叫作modifiers或者mutators)。
  • Queries(查詢) - 返回值而且不會改變對象的狀態。

架構圖:

無論DDD也好,CQRS也好,其實這兩種都不會100%適合全部的項目架構的,這就須要架構師結合項目自己特色及需求有所選擇,可是其中的思想咱們能夠運用在項目的任何地方。

基於消息的分佈式:

其實無論使用怎樣的架構,加入怎樣的架構思想(soa),核心或者是開發者最想達到的就是層次,系統之間的解耦,複雜的東西沒人會喜歡。

隨着系統的發展,咱們的程序會涉及到多臺服務器,多種終端,同時爲了解耦咱們引入了基於消息的分佈式架構。

首先,因此係統的通訊基於消息,邏輯聯繫不會涉及到具體的業務實現,同時消息的傳遞更加的廉價可適配多種終端。

其次,因爲所用邏輯只是基於消息實現,迭代的成本也會相對於其餘耦合項目更快更方便。

展現層:

隨之Web2.0的到來單一頁面展現的信息也更加的豐富,Ajax,js的流行也使得Ui端的操做也越發變重,因而你們有指望以一種工程的思想去擁抱這種變化,因而MVVM,js的Mvc框架陸續出現。同時隨着移動互聯網的興起,不一樣終端對於系統的對接也很是重要,因而咱們考慮在Ui與Logic之間引入Application或Service層應對不一樣終端配置。

如:咱們在Client Presenter Layer 上加入WCF適配多種終端提交的訂單,都是創建在消息基礎之上的,樓主以前作電商系統是針對於來自淘寶,天貓,亞馬遜訂單時,爲避免出現對庫中訂單併發,產生「超買」狀況,採用了在上層Ui與logic層之間引入了OrderChannel層,將不一樣終端訂單進行排隊的解決方案。

以上是架設一個可以適配不一樣需求的架構過程,可是真正的真理是須要你們在實踐中,錯誤中汲取的。

下面是樓主簡單的小分層架構,不妥,不足之處但願你們指導斧正。

層次劃分:

爲了實現單獨部署,層次解耦因此層次之間是基於接口實現的。

DataAccess層引入倉儲實現統一DTO操做,實現基於Ef:

IRepository:

  1. public interface IRepository<T> where T:class 
  2.     {  
  3.         IEnumerable<T> FindAll(Expression<Func<T,bool>> exp);  
  4.         void Add(T entity);  
  5.         void Delete(T entity);  
  6.         void Submit();  
  7.     } 

引入RepositoryBase實現接口定義:

  1. public class RepositoryBase<T>:IRepository<T> where T:class 
  2.     {  
  3.         DbContext context;  
  4.         public RepositoryBase(DbContext _context)  
  5.         {  
  6.             context = _context;  
  7.         }  
  8.  
  9.         public RepositoryBase() {  
  10.             this.context = new TestDBEntities();  
  11.         }  
  12.  
  13.         public IEnumerable<T> FindAll(Expression<Func<T, bool>> exp)  
  14.         {  
  15.             return context.Set<T>().Where(exp);  
  16.         }  
  17.  
  18.         public void Add(T entity)  
  19.         {  
  20.             context.Set<T>().Add(entity);  
  21.         }  
  22.  
  23.         public void Delete(T entity)  
  24.         {  
  25.             context.Set<T>().Remove(entity);  
  26.         }  
  27.  
  28.         public void Submit()  
  29.         {  
  30.             context.SaveChanges();  
  31.         }  
  32.     } 

這對於單一的某個倉儲咱們單獨引入其自身的倉儲接口:

  1. public interface IUserRepository:IRepository<UserTest>  
  2. {  
  3.     IList<UserTest> GetAllById(int id);  
  4.  
  5.     bool CheckUserExist(UserTest u);  

特定倉儲實現:

  1. public class UserRepository : RepositoryBase<UserTest>,IUserRepository  
  2.     {  
  3.         public IList<UserTest> GetAllById(int id)  
  4.         {  
  5.             using (TestDBEntities entities=new TestDBEntities())  
  6.             {  
  7.                 var users = from u in entities.UserTests  
  8.                             where u.ID == id  
  9.                             select u;  
  10.                 return users.ToList();  
  11.             }  
  12.         }  
  13.  
  14.         public bool CheckUserExist(UserTest u)  
  15.         {  
  16.             using (TestDBEntities entities = new TestDBEntities())  
  17.             {  
  18.                 List<UserTest> users = entities.UserTests.Where(ut => ut.UserName == u.UserName && ut.UserPassword==u.UserPassword).ToList<UserTest>();  
  19.                 return users.Count==0 ? false : true;  
  20.             }  
  21.         }  
  22.     } 

在Service層一樣創建相關接口適配特種服務:

IUserCore:

  1. public interface IUserCore  
  2.     {  
  3.         CommandStatueEnum UserLogin(IModel model);  
  4.         CommandStatueEnum UserRegister(IModel model);  
  5.  
  6.         List<UserTest> GetUsers(Expression<Func<UserTest, bool>> expr);  
  7.     } 

UserCore:

  1. public class UserCore : IUserCore  
  2.     {  
  3.         #region Structure  
  4.         IUserRepository _repository;  
  5.         public UserCore(IUserRepository repository) {  
  6.             this._repository = repository;  
  7.         }  
  8.         #endregion  
  9.  
  10.         public CommandStatueEnum UserLogin(IModel model)  
  11.         {  
  12.             try 
  13.             {  
  14.                 UserLogin u = model as UserLogin;  
  15.                 UserTest uTest = new UserTest();  
  16.                 uTest.UserName = u.UserName;  
  17.                 uTest.UserPassword = u.Password;  
  18.  
  19.                 if (_repository.CheckUserExist(uTest))  
  20.                 {  
  21.                     return CommandStatueEnum.Succeed;  
  22.                 }  
  23.                 else 
  24.                 {  
  25.                     return CommandStatueEnum.Fail;  
  26.                 }  
  27.             }  
  28.             catch (Exception ex) {  
  29.                 throw ex;  
  30.             }  
  31.         }  
  32.  
  33.         public CommandStatueEnum UserRegister(IModel model)  
  34.         {  
  35.             try 
  36.             {  
  37.                 UserLogin u = model as UserLogin;  
  38.                 UserTest uTest = new UserTest() { UserName=u.UserName, UserPassword=u.Password};  
  39.                 _repository.Add(uTest);  
  40.                 _repository.Submit();  
  41.                 return CommandStatueEnum.Succeed;  
  42.             }  
  43.             catch (Exception ex)  
  44.             {  
  45.                 throw ex;  
  46.             }  
  47.         }  
  48.  
  49.  
  50.         public List<UserTest> GetUsers(System.Linq.Expressions.Expression<Func<UserTest, bool>> expr=null)  
  51.         {  
  52.            return _repository.FindAll(expr).ToList<UserTest>();  
  53.         }  
  54.     } 

Controller:

  1. public class AccountController : Controller  
  2.     {  
  3.         IUserCore userCore;  
  4.         public AccountController(IUserCore _userCore)  
  5.         {  
  6.             this.userCore = _userCore;  
  7.         }  
  8.  
  9.         //  
  10.         // GET: /Account/  
  11.  
  12.         #region view  
  13.         public ActionResult Home()  
  14.         {  
  15.             ViewBag.Users = userCore.GetUsers(u=>u.IsUse==1);  
  16.             return View();  
  17.         }  
  18.  
  19.         public ActionResult Login()  
  20.         {  
  21.             return View();  
  22.         }  
  23.  
  24.         public ActionResult Register()  
  25.         {  
  26.             return View();  
  27.         }  
  28.         #endregion  
  29.  
  30.         #region Post  
  31.         [HttpPost]  
  32.         public ActionResult Login(UserLogin account)  
  33.         {  
  34.             try 
  35.             {  
  36.                 if (userCore.UserLogin(account) == CommandStatueEnum.Succeed)  
  37.                 {  
  38.                     return RedirectToAction("Home");  
  39.                 }  
  40.                 else 
  41.                 {  
  42.                     return View();  
  43.                 }  
  44.             }  
  45.             catch (Exception ex)  
  46.             {  
  47.                 ExceptionModel.IsExcept = true;  
  48.                 ExceptionModel.Exception = ex.ToString();  
  49.                 ExceptionModel.CreateTime = DateTime.Now;  
  50.                 return View();  
  51.             }  
  52.         }  
  53.  
  54.         [HttpPost]  
  55.         public ActionResult Register(UserLogin account)  
  56.         {  
  57.             try 
  58.             {  
  59.                 if (userCore.UserRegister(account) == CommandStatueEnum.Succeed)  
  60.                 {  
  61.                     return RedirectToAction("Home");  
  62.                 }  
  63.                 else 
  64.                 {  
  65.                     return View();  
  66.                 }  
  67.             }  
  68.             catch (Exception ex)  
  69.             {  
  70.                 ExceptionModel.IsExcept = true;  
  71.                 ExceptionModel.Exception = ex.ToString();  
  72.                 ExceptionModel.CreateTime = DateTime.Now;  
  73.                 return View();  
  74.             }  
  75.         }  
  76.         #endregion  
  77.     } 

對於接口之間咱們經過引入IOC工具解耦:

  1. public class MvcApplication : System.Web.HttpApplication  
  2.     {  
  3.         protected void Application_Start()  
  4.         {  
  5.             AreaRegistration.RegisterAllAreas();  
  6.  
  7.             WebApiConfig.Register(GlobalConfiguration.Configuration);  
  8.             FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);  
  9.             RouteConfig.RegisterRoutes(RouteTable.Routes);  
  10.             BundleConfig.RegisterBundles(BundleTable.Bundles);  
  11.             AuthConfig.RegisterAuth();  
  12.  
  13.             #region IOC  
  14.             var builder = new ContainerBuilder();  
  15.             SetupResolveRules(builder);  
  16.             builder.RegisterControllers(Assembly.GetExecutingAssembly());  
  17.             var container = builder.Build();  
  18.             DependencyResolver.SetResolver(new AutofacDependencyResolver(container));  
  19.             #endregion  
  20.         }  
  21.  
  22.         private void SetupResolveRules(ContainerBuilder builder)  
  23.         {  
  24.             //Components are wired to services using the As() methods on ContainerBuilder  
  25.             builder.RegisterType<UserCore>().As<IUserCore>();  
  26.             builder.RegisterType<UserRepository>().As<IUserRepository>();  
  27.         }  
  28.  
  29.     } 

其餘基礎類庫咱們會結合具體需求進行定製,上面例子多有不妥之處只起演示之用。

綜上所述,本篇只起拋磚引玉之用,還請大牛拍磚指導。

原文連接:http://www.cnblogs.com/xiguain/p/3636022.html

相關文章
相關標籤/搜索