.net架構設計讀書筆記--第二章 第7節 神化般的業務層

1、編排業務邏輯的模式
1. 事務腳本模式TSThe Transaction Script pattern 
git

  • TS模式概述

    TS 鼓勵你跳過任何的面向對象的設計,你直接到所需的用戶操做的業務組件映射。專一於的業務用戶能夠經過表示層完成,併爲每一個請求編寫方法。這個方法被稱之爲事務腳本,此處事務一般是指想要進行商業交易,腳本是指系統中的一系列關係用戶操做的系統操做。 github

    TS歷時多年仍然不過期的緣由只有一個:它基於推行可視化的業務邏輯設計,而可視化正上用戶體驗的核心。 web

    TS中,每一個用戶操做都在上下文的物理事務邊界中完成。不一樣於數據訪問層的數據執行腳本,TS的數據訪問一般被封裝在數據個組件中。按照設計,TS不包含使用面向對象設計。TS中的任務邏輯都是If,while,for等組成。 數據庫

  • TS模式實際應用

    在實現中每一個TS都是一個單獨的,可能表現爲一個類的靜態方法,能夠在每一個類本身執行TS。當你這樣作的時候,就已經完美演繹了命令模式。 設計模式

    命令模式的主要設計思想是用一個對象來表示動做。命令對象封裝一個動做和它全部的參數。典型的,命令對象公開的標準接口,以便調用方能夠調用任何命令,而無需關注命令類的具體行爲。如: api

public interface IApplicationCommand 架構

{ mvc

    int Run(); app

} asp.net

 

public class BookHotelRoom : IApplicationCommand

{

    Customer _guest;

    DateTime _checkIn, _checkOut;

    String _confirmationNumber;

    // other internal members 

 

    public BookHotelRoom(Customer guest, DateTime checkIn, DateTime checkOut)

    {

        _guest = guest;

        _checkIn = checkIn;

        _checkOut = checkOut;

    }

    public String ConfirmationNumber

    {

        get { return _confirmationNumber; }

    }

 

    public int Run()

    {

        // Start the transaction  

        // Check room availability for requested stay 

        // Check customer information?(already guest, payment method, preferences) 

        // Calculate room rate  

        // Add a new record to the Bookings database table 

        // Generate the confirmation number 

        // Commit the transaction???????  

        // E-mail the customer 

        // Store the confirmation number to the local member _confirmationNumber 

    } 

 

    ...  

}

TS模式不對任務數據設計權限,不也會對數據作任何轉換。它只用用於接收和發送數據,因此一般的作法是使用數據類(Dto)來傳遞數據。

 

2. 域模型模式(The Domain Model pattern)

域模型(DM)一般在DDD設計中使用,但也不侷限於它。DM也是一個經常使用的設計模式,它讓架構師側重於系統的預期行爲和運行時的數據流。

  • DM模式概述

    域模型是不一樣於對象模型的一系列集合。域模型忠實於表示業務領域,特別是域內進程的數據流。

  • DM模式實際應用

    域模型是一系列表示業務領域的plain old classes。這些類是數據容器,能夠表現爲屬性也能夠是方法。The term POCO (Plain Old CLR Object)一般指這些域模型。

    實際使用咱們不關注類自己,關注的是行爲和事件。這些行爲能幫助你理解在類上發生了什麼。着眼於行爲比着眼於類屬性更有用,另外一方面看來,這就是Tell-Don't-Ask原則的體現。

    有些時候域模型須要被持久化,而持久化不是域模型的職責,持久化將在基礎結構層才能被實現。從應用程序看來域模型是業務邏輯數據庫,不依賴任何接口,而持久化依賴接口,使用關係模型來持久化。域模型和關係模型一般要經過ORM工具來完成,如Microsoft's Entity Framework 和 NHibernate

   

3.反域模式ADM(The Anemic Domain Model (anti-)pattern)

 域模式的核心於對象關聯的行爲,"行爲先行"是違背域模型設計原則的,因此產生了另一種模式,反域模式(ADM)。

  • ADM概述

    ADM域模型中,全部對象仍然都遵循命名約定的真實世界域實體、 實體之間的關係仍存在,和模型的總體結構緊密匹配的真實域空間。沒有行爲,只有屬性的實體。

    ADM模式建議不要在域對象裏聽任何邏輯。全部的邏輯都被放在邏輯領域的服務組件裏。這此服務是域模型的消費者,而且有存儲和持久化的功能。

  ■ Analysis leads to objects that closely model the domain space and are tailored to the real 

needs 

  ■ The strong domain perspective of things reduces the risk of misunderstandings between the 

domain experts and the development team 

  ■ Code is likely to become more readable and easily understandable 

  ■ The fnal result has more chances to really be close to expectations.

 

2、將關注點從數據轉移到任務

1. Asp.net Mvc中的任務

    用戶行爲最終被實現爲controller類中的一個方法調用。controller應該是被用來組織任務的首選。抽象的說,Contrller與WebForm中的postback事件沒有區別。在這兩個方法中,聰明的開發人員都會爲了不web form中的完整的事件執行而選擇使用Controller。

  • Controller是一個協調者

    Responsibility-Driven Design (RDD)職責驅動設計由Rebecca Wirfs-Brock 和Alan McKean提出:Roles, Responsibilities, and Collaborations。RDD的本質是將系統分解成一系統可執行的Action動做,而後每一個action被映射到一個組件類。執行action被設計成組件類的職責。組件的解決依賴於它設定的職責。

    Asp.net mvc 的controller是RDD模式的一個生動的實現,RDD協調者建議將action分組到一系統application services中,由controller 調用services來執行action返回view model

public ActionResult PlaceOrder(OrderInputModel orderInfo) 

    // Input data already mapped thanks to the model binding  

    // infrastructure of ASP.NET MVC 

 

    // Perform the task invoking a application service and 

    // get a view model back from application layer 

    var service = new OrderService(); 

    var model = service.PlaceOrder(); 

 

    // Invoke next view 

    return View(model); 

}

 

controller負責展示層和應用層的協調調用,這種狀況下若是須要不一樣的展示層,能夠用如下代碼輕鬆實現:

var service = new OrderService(); 

var model = service.PlaceOrder(); 

 

// Adapt to the new view model 

var newFrontendModel = someAdapter.NewViewModel(response);  

 

  • 鏈接應用層和展示層 Connecting the application and presentation layers

    應用層和展示層的鏈接點是controller,使用依賴倒置模式Ioc容器如microsoft unity來重寫asp.net mvc的controller factory:

var factory = new UnityControllerFactory(); 

ControllerBuilder.Current.SetControllerFactory(factory);

 

UnityControllerFactory實現以下:

public class UnityControllerFactory : DefaultControllerFactory 

   public static IUnityContainer Container { get; private set; } 

   public UnityControllerFactory() 

   { 

      Container = new UnityContainer();   // Initialize the IoC 

      Container.LoadConfiguration();      // Configure it reading details from web.config 

   } 

   protected override IController GetControllerInstance(RequestContext context, Type type) 

   { 

       if (type == null)  return null; 

       return Container.Resolve(type) as IController; 

   } 

}

而後每一個controller類的默認構造函數要改爲以下:

public class HomeController 

    private IHomeService _service; 

    public HomeController(IHomeService service) 

    { 

       _service = service; 

    } 

    ... 

}

    You can use the Unity Mvc library available as a NuGet package  For more  information,  see http://github com/feedbackhound/Unity Mvc5 

      

 

  • 鏈接應用層和數據訪問層 Connecting the application and data-access layers

    一樣的問題存在於數應用層和基礎架構層的數據訪問。使用相同的方法——依賴注入。在域模型場景中的數據訪問邏輯容器一般被命名爲repository

public class HomeService 

    private ISomeEntityRepository _someEntityRepo; 

    public HomeService(ISomeEntityRepository repo) 

    { 

       _someEntityRepo = repo; 

    } 

    ... 

}

有意思的是,你不須要在代碼中修改初始化controller來設置factory,你只要確保倉儲類型和接口都映射到Ioc容器裏就能夠。全部Ioc容器都提供配置和api兩方式來映射類型。因此不須要再經過代碼來配置,如今的IoC容器都提供了這種透明的方式來解決依賴關係。若是你通知IoC容器獲取一個Controller類型,這個controller類型依賴一些Application Services類型,反過來,Services類型又依賴一個或多個倉儲類型,全部這些代碼都在一行代碼裏解決。

    層與層之間的鏈接通訊建議使用依賴注入實現,但它不是惟一的解決方案。若是你有多個層在同一個進程空間內,比較簡單的方法是直接而且本地實例化對象,不論他們在application layers、servces layers或是respositories layers. 缺點就是他們會在層之間產生高偶合。

// Tight coupling between the class OrderService  

// and the class that contains this code 

var service = new OrderService(); 

var model = service.PlaceOrder();

 

2. 編排域內的任務

    一般、應用程序的邏輯層包含了任務編排、域邏輯和一些其它的東西。

  • 跨實體域邏輯

    域名服務一般包含業多個域實體操做的業務邏輯。大多狀況下,域名服務是複雜、 多步的操做,都在域的邊界內進行,並有多是基礎設施層(infrastructure)。典型的例子是OrderProcessor, BestPriceFinder, 或GoldCustomerEvaluator這樣的域服務。服務的命名以功能命名,而且可讓領域專家和相關人員容易理解。

 

3、跨邊界傳遞數據

    表示層物理邊界跨界,不管是進程跨界仍是物理計算機跨界都是一項很昂貴的操做。訪問一個遠程計算機的效率可能要比進程內通訊慢100倍。

1.層架構間的數據流

    下圖表示分層架構一個抽象的數據流。當執行一個命令執行時,數據流從用戶接口以一個input model形勢進入應用層。鑑於這個請求動做,應用程序層須要一系列用來作爲input model的域模型實例。在一個領域分層系統中,持久性特指將轉換成物理模型,媽實體關係模型(relational-data model),在返回結果時將data mode再轉換爲demain model。

 

 

理論上講,一個分層的系統由上圖的4種邏輯分離的model組成,但在有的狀況下他們是一致的。data model一般與demain model在基礎設施層是一致的。在Asp.net mvc應用程序中,input model與output model一般是同一個model。

  • 共享域模型實體(Sharing the Domain Model entities)

在遵循域模型配置設計的架構中,域實體與數據緊密相關,推薦將域模型向表示層冒泡,而且在必要的時候將他們序列化來傳輸。

 

  • 使用數據傳輸對象

在一個解決方案中不多能讓一個實知足整個系統的須要,畢竟不一樣的層可能對數據要求不同。有些狀況下,爲了便捷使在全部層中都使用了demain model,有些狀況下須要使用Dto類,總之、跟據你的須要。

  •     Dto對象概述(data-transfer object)

    Dto被設計爲用來作物理層之間的數據載體。Dto類只有屬性,沒有行爲。Dto原生能夠被序列化,在遠程組件調用中一般這樣作。

 

  • DTOs 與. domain entities區別

典型的DTO使用如:顯示和處理一個自定義訂單。在處理訂單時須要大量的數據,顯示數據時只須要簡單少許數據。DTO增長了層次的複雜度,可是減小了容器的複雜度。

 

 

  • AutoMapper 和適配器

    Data model 與DTO之是能夠經過AutoMapper適配器完成自動轉換。

Mapper.CreateMap<YourSourceType, YourDtoType>();

Once a mapping is defned, you invoke it via the Map method:

var dto = Mapper.Map<YourDtoType>(sourceObject);

相關文章
相關標籤/搜索