日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
從業(yè)務(wù)域驅(qū)動(dòng)開(kāi)發(fā)看三層架構(gòu)夠不夠?

三層架構(gòu)

成都創(chuàng)新互聯(lián)堅(jiān)信:善待客戶,將會(huì)成為終身客戶。我們能堅(jiān)持多年,是因?yàn)槲覀円恢笨芍档眯刨?。我們從不忽悠初訪客戶,我們用心做好本職工作,不忘初心,方得始終。十余年網(wǎng)站建設(shè)經(jīng)驗(yàn)成都創(chuàng)新互聯(lián)是成都老牌網(wǎng)站營(yíng)銷服務(wù)商,為您提供成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、H5建站、網(wǎng)站制作、成都品牌網(wǎng)站建設(shè)、微信小程序服務(wù),給眾多知名企業(yè)提供過(guò)好品質(zhì)的建站服務(wù)。

相對(duì)于目前日新月異的新概念,新名詞,三層架構(gòu)已經(jīng)算得上元老了。雖仍有爭(zhēng)議,但業(yè)界更多的是共識(shí)。

圖1 常用三層的描述圖

足夠簡(jiǎn)單、清晰,我仍要提醒的是,注意層之間連線的箭頭,非常之重要,借用UML的定義,箭頭表示依賴關(guān)系。也就是說(shuō),必須先有數(shù)據(jù)層,才有業(yè)務(wù)層,然后才有表現(xiàn)層。這又怎么樣,小問(wèn)題。不,這是一個(gè)大麻煩!

從DDD看三層

我們暫時(shí)靶這個(gè)話題放一放,挑個(gè)比較新一點(diǎn)的東西。業(yè)務(wù)域驅(qū)動(dòng)開(kāi)發(fā)(DDD) 近年也是風(fēng)生水起,紅紅火火,但它是什么,是怎么回事,似乎就不如三層架構(gòu)那么婦孺皆知了。

圖2 從DDD的角度看三層架構(gòu)

以業(yè)務(wù)域?yàn)橄到y(tǒng)的核心,所有其它與業(yè)務(wù)無(wú)關(guān)的內(nèi)容對(duì)這個(gè)核心來(lái)談,都是外部服務(wù)/功能。這里,出于本文說(shuō)明的需要,獨(dú)立出了兩個(gè)較為特別的外部功能,持久層和用戶接口。

兩個(gè)看上去完全不同的架構(gòu)設(shè)計(jì),哪個(gè)更對(duì)哪個(gè)更好?每一個(gè)都有大量的擁護(hù)者,大量的討論,互相三間似乎又涇渭分明,至少我們經(jīng)??吹降奈恼陆o我們?nèi)绱说挠∠蟆W匀?,我們的思考,為什么不能融合在一起呢?其?shí),它們并不像看起來(lái)區(qū)別那么大。從名詞上,雖然我有意把名稱錯(cuò)開(kāi),我們也仍能看到之間的對(duì)應(yīng)關(guān)系、業(yè)務(wù)層=業(yè)務(wù)域,數(shù)據(jù)層=持久層,表現(xiàn)層=用戶接口。當(dāng)然,這些細(xì)節(jié)用詞的不同仍有必要的,畢竟,它們不完全是一回事。

DDD的三層實(shí)現(xiàn)詳細(xì)架構(gòu)

好了,抽象的討論已經(jīng)足夠了,我們也足夠糊涂了。細(xì)節(jié)為王,我們?nèi)绾螌?shí)現(xiàn)?來(lái)看看這個(gè)實(shí)際系統(tǒng)的簡(jiǎn)化架構(gòu)圖。.

圖3 實(shí)際架構(gòu)設(shè)計(jì)

可以看到,在保留了清晰的三層外,重要的是把依賴關(guān)系改變了。而所謂依賴注入(DI),只是一種實(shí)際的技術(shù)實(shí)現(xiàn),完成和實(shí)現(xiàn)這種架構(gòu)設(shè)計(jì)需求。也可以清晰的看到,圖中是以Domain為核心的。 當(dāng)然,這是一個(gè)簡(jiǎn)化又簡(jiǎn)化的示意圖,不想一開(kāi)始就把事情弄的復(fù)雜.

看代碼

最后,來(lái)看看具體的代碼,才有更好的體驗(yàn)。

業(yè)務(wù)域 (Domain)

考試類:

 
 
 
 
  1. ?namespace Skight.Demo.Domain.Examination{
  2. public class Exam{public virtual int Id { get; set; }
  3. public virtual string Code { get; set; }
  4. public virtual string Name { get; set; }}}

view raw gistfile1.cs This Gist brought to you by GitHub.

很簡(jiǎn)單的一個(gè)考試類,可以看到,域中的類定義幾乎不受持久層(數(shù)據(jù)庫(kù))影響,除了兩點(diǎn):

1.屬性ID是從數(shù)據(jù)表的主鍵而來(lái);

2. 如果要用nHibernate的Lazy Load每個(gè)屬性都必須是Virtual。

即使如此,這個(gè)類已經(jīng)足夠干凈了。我也看到,一些系統(tǒng)實(shí)現(xiàn),專門定義了一個(gè)基礎(chǔ)類Entity,然后,把ID的定義放在這個(gè)類中. 我覺(jué)得很沒(méi)必要, 畫(huà)蛇添足。

作為示例,這個(gè)域類很簡(jiǎn)單, 但卻是核心的核心。項(xiàng)目越往后,這一層膨脹的越厲害。后面幾部分,現(xiàn)在看起來(lái)比較多,復(fù)雜。之后,不會(huì)有大的變化,反而顯得會(huì)越來(lái)越簡(jiǎn)單。

倉(cāng)儲(chǔ)接口:

 
 
 
 
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq.Expressions; 
  4. namespace Skight.Demo.Domain{
  5. public interface Repository{Item get_by_id(int id); 
  6. void save(Item item); 
  7. Item get_single_item_matching(Query query);
  8. void delete(Item item); 
  9. IEnumerable get_all_items_matching(Query query);
  10. IEnumerable get_all_items();}}

view raw gistfile1.cs This Gist brought to you by GitHub.

注意到:

1. 接口命名,我沒(méi)有加I,這是特意的。

2. 用到了Query<>接口, 這個(gè)是對(duì)查詢的一個(gè)抽象。好處是,不需要像大多數(shù)的倉(cāng)儲(chǔ)實(shí)現(xiàn),要為每個(gè)類建立一個(gè)倉(cāng)儲(chǔ)接口,膨脹的很厲害。

Quer接口很簡(jiǎn)單,沒(méi)有任何方法和屬性,只是為了使用強(qiáng)類型。它的實(shí)現(xiàn)類會(huì)根據(jù)需要, 越來(lái)越多。 因?yàn)?查詢幾乎就是數(shù)據(jù)層的主要功能。

查詢接口的定義:

 
 
 
 
  1. namespace Skight.Demo.Domain
  2. {
  3. public interface Query{}
  4. }

view raw gistfile1.txt This Gist brought to you by GitHub.

持久層 (數(shù)據(jù)層)

考試映射類:

 
 
 
 
  1. using FluentNHibernate.Mapping;
  2. using Skight.Demo.Domain.Examination; 
  3. namespace Skight.Demo.NHRepository{
  4. public class ExamMap:ClassMap{
  5. public ExamMap(){Id(x => x.Id);Map(x => x.Code);
  6. Map(x => x.Name);}}}

view raw gistfile1.cs This Gist brought to you by GitHub.

Fluent nHibernate對(duì)倉(cāng)儲(chǔ)接口的實(shí)現(xiàn):

 
 
 
 
  1. using System;using System.IO;
  2. using System.Reflection;
  3. using FluentNHibernate.Cfg;
  4. using FluentNHibernate.Cfg.Db;
  5. using NHibernate;using NHibernate.Cfg;
  6. using NHibernate.Tool.hbm2ddl;
  7. namespace Skight.Demo.NHRepository{    
  8. public class SessionProvider    
  9. {       
  10.  #region Instance for use outside        
  11. private static SessionProvider instance;        
  12. public static SessionProvider Instance {           
  13.  get            {               
  14.  if (instance == null)                
  15. {                   
  16.  instance = new SessionProvider();        
  17.         }                
  18. return instance;          
  19.   }        }     
  20.    #endregion      
  21.   #region Set up database     
  22.    private const string DBFile = "SkightDemo.db";   
  23.      public bool IsBuildScheme { get; set; }   
  24.      public void initilize()    
  25.     {                       session_factory = Fluently.Configure()          
  26.       .Database(SQLiteConfiguration.Standard.UsingFile(DBFile).ShowSql())         
  27.        .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))         
  28.       .ExposeConfiguration(c => c.SetProperty("current_session_context_class", "thread_static"))        
  29.        .ExposeConfiguration(build_schema)            
  30.     .BuildSessionFactory();        }    
  31.     private void build_schema(Configuration configuration)    
  32.     {            if (IsBuildScheme)      
  33.       {                new SchemaExport(configuration)         
  34.            .Execute(true, true, false);          
  35.   }        }        #endregion     
  36.    private readonly object lock_flag = new object();   
  37.      private ISessionFactory session_factory;     
  38.    public ISessionFactory SessionFactory {         
  39.    get {               
  40.  if (session_factory == null) {     
  41.                lock (lock_flag) {                      
  42.   if (session_factory == null) {                       
  43.      initilize();                     
  44.    }                    }             
  45.    }              
  46.   return session_factory;       
  47.      }        }        
  48. public ISession CreateSession() {       
  49.      ISession session = SessionFactory.OpenSession();         
  50.    return session;      
  51.   }        
  52. public ISession CurrentSession    
  53.     {        
  54.     get { return SessionFactory.GetCurrentSession(); }    
  55.     }   
  56.  }}

view raw gistfile1.cs This Gist brought to you by GitHub.

Fluent nHibernate的配置:

view raw gistfile1.cs This Gist brought to you by GitHub.

使用的SQLite文本數(shù)據(jù)庫(kù),作為示例。

測(cè)試和使用的例子

自動(dòng)創(chuàng)建數(shù)據(jù)庫(kù):

 
 
 
 
  1. using NUnit.Framework; 
  2. namespace Skight.Demo.NHRepository.Tests{[TestFixture]
  3. public class CreateDatabase{[Test]public void Run(){
  4. var provider = SessionProvider.Instance;provider.IsBuildScheme = true;provider.initilize();}
  5.  }}

view raw gistfile1.cs This Gist brought to you by GitHub.

這里,只是用測(cè)試的形式,實(shí)現(xiàn)功能。如果運(yùn)行這個(gè)測(cè)試,將自動(dòng)生成數(shù)據(jù)庫(kù)。并且,可以輸顯示數(shù)據(jù)庫(kù)生成腳本。在產(chǎn)品環(huán)境下,我就是用這個(gè)腳本來(lái)做數(shù)據(jù)庫(kù)安裝的。

操作數(shù)據(jù)(模擬UI):

 
 
 
 
  1. using NHibernate;
  2. using NHibernate.Context;
  3. using NUnit.Framework;
  4. using Skight.Demo.Domain;
  5. using Skight.Demo.Domain.Examination; 
  6. namespace Skight.Demo.NHRepository.Tests{[TestFixture]
  7. public class DataOperation{
  8. private Repository repository;
  9. private ISession session;private ITransaction transaction;
  10. [SetUp]public void SetUp(){
  11. //Dependecy Injectrepository=new RepositoryImpl();
  12. session = SessionProvider.Instance.CreateSession();
  13. transaction = session.BeginTransaction();
  14. CurrentSessionContext.Bind(session);
  15. }[TearDown]public void TearDown(){ 
  16. transaction.Commit();
  17. transaction.Dispose();
  18. transaction = null; 
  19. session.Close();
  20. session.Dispose();
  21. }[Test]public void create_a_exam(){var exam = new Exam();
  22. exam.Code = "001";exam.Name = "計(jì)算機(jī)考試";
  23. repository.save(exam);
  24. [Test]public void get_the_exam_by_id(){
  25. var exam = repository.get_by_id(1);
  26. Assert.IsNotNull(exam);
  27. [Test]public void delete_the_exam() 
  28. {var exam = repository.get_by_id(1);repository.delete(exam);
  29. }}

view raw gistfile1.cs This Gist brought to you by GitHub.

同樣,用測(cè)試的形式,模擬UI的數(shù)據(jù)的操作。
首先,運(yùn)行Create_a_exam()插入一個(gè)考試對(duì)象。
然后,運(yùn)行g(shù)et_the_exam_by_id()獲取剛插入的考試。
運(yùn)行 delete_the_exam()刪除考試。

完全代碼下載  下載頁(yè)面     直接下載


文章名稱:從業(yè)務(wù)域驅(qū)動(dòng)開(kāi)發(fā)看三層架構(gòu)夠不夠?
新聞來(lái)源:http://www.dlmjj.cn/article/dhdcgpi.html