成都一家集口碑和實(shí)力的網(wǎng)站建設(shè)服務(wù)商,擁有專業(yè)的企業(yè)建站團(tuán)隊(duì)和靠譜的建站技術(shù),十載企業(yè)及個(gè)人網(wǎng)站建設(shè)經(jīng)驗(yàn) ,為成都數(shù)千家客戶提供網(wǎng)頁設(shè)計(jì)制作,網(wǎng)站開發(fā),企業(yè)網(wǎng)站制作建設(shè)等服務(wù),包括成都營銷型網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),同時(shí)也為不同行業(yè)的客戶提供成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè)的服務(wù),包括成都電商型網(wǎng)站制作建設(shè),裝修行業(yè)網(wǎng)站制作建設(shè),傳統(tǒng)機(jī)械行業(yè)網(wǎng)站建設(shè),傳統(tǒng)農(nóng)業(yè)行業(yè)網(wǎng)站制作建設(shè)。在成都做網(wǎng)站,選網(wǎng)站制作建設(shè)服務(wù)商就選創(chuàng)新互聯(lián)建站。
規(guī)范模式是一種特定的軟件設(shè)計(jì)模式,通過使用布爾邏輯 (維基百科)將業(yè)務(wù)規(guī)則鏈接在一起,可以重新組合業(yè)務(wù)規(guī)則。
在實(shí)際中,它主要用于 為實(shí)體或其他業(yè)務(wù)對象定義可重用的過濾器。
在本節(jié)中,我們將看到需要規(guī)格模式。本節(jié)是通用的,與ABP的實(shí)現(xiàn)無關(guān)。
假設(shè)您有一種服務(wù)方法來計(jì)算客戶的總數(shù),如下所示:
public class CustomerManager { public int GetCustomerCount() { // TODO ... return 0 ; } }
您可能希望通過過濾器獲得客戶數(shù)量。例如,您可能會(huì)有高級(jí)客戶(其余額超過10萬美元),或者您可能想要通過 注冊年度過濾客戶。然后,您可以創(chuàng)建其他方法,如GetPremiumCustomerCount(), GetCustomerCountRegisteredInYear(int year), GetPremiumCustomerCountRegisteredInYear(int year)等。由于您有更多的標(biāo)準(zhǔn),因此無法為每種可能性創(chuàng)建組合。
這個(gè)問題的一個(gè)解決方案是規(guī)范模式。我們可以創(chuàng)建一個(gè)獲取參數(shù)作為過濾器的方法:
public class CustomerManager { private readonly IRepository<Customer> _customerRepository; public CustomerManager(IRepository<Customer> customerRepository) { _customerRepository = customerRepository; } public int GetCustomerCount(ISpecification<Customer> spec) { var customers = _customerRepository.GetAllList(); var customerCount = 0; foreach (var customer in customers) { if (spec.IsSatisfiedBy(customer)) { customerCount++; } } return customerCount; } }
因此,我們可以獲得任何對象作為實(shí)現(xiàn) ISpecification <Customer>接口的參數(shù),定義如下:
public interface ISpecification<T>{ bool IsSatisfiedBy(T obj); }
我們可以與客戶一起致電IsSatisfiedBy,以測試該客戶是否有意。因此,我們可以使用相同的GetCustomerCount與不同的過濾器,而不改變方法本身。
雖然這個(gè)解決方案在理論上是相當(dāng)不錯(cuò)的,但應(yīng)該改進(jìn),以更好地在C#中工作。例如,它是沒有效率得到所有客戶提供從數(shù)據(jù)庫來檢查它們是否滿足給定的規(guī)格/條件。在下一節(jié)中,我們將看到ABP的實(shí)現(xiàn),克服了這個(gè)問題。
ABP定義了ISpecification界面,如下所示:
public interface ISpecification<T>{ bool IsSatisfiedBy(T obj); Expression<Func<T, bool>> ToExpression(); }
添加ToExpression()方法,該方法返回一個(gè)表達(dá)式,并用于更好地與IQueryable和 Expression樹的集成。因此,我們可以輕松地將規(guī)范傳遞給存儲(chǔ)庫,以在數(shù)據(jù)庫級(jí)別應(yīng)用過濾器。
我們通常從規(guī)范<T>類繼承,而不是直接實(shí)現(xiàn)ISpecification <T>接口。規(guī)范類自動(dòng)實(shí)現(xiàn)IsSatisfiedBy方法。所以,我們只需要定義ToExpression。我們來創(chuàng)建一些規(guī)范類:
//Customers with $100,000+ balance are assumed as PREMIUM customers.public class PremiumCustomerSpecification : Specification<Customer>{ public override Expression<Func<Customer, bool>> ToExpression() { return (customer) => (customer.Balance >= 100000); } }//A parametric specification example.public class CustomerRegistrationYearSpecification : Specification<Customer>{ public int Year { get; } public CustomerRegistrationYearSpecification(int year) { Year = year; } public override Expression<Func<Customer, bool>> ToExpression() { return (customer) => (customer.CreationYear == Year); } }
如你所見,我們只是實(shí)現(xiàn)了簡單的lambda表達(dá)式 來定義規(guī)范。讓我們使用這些規(guī)格來獲得客戶數(shù)量:
count = customerManager.GetCustomerCount(new PremiumCustomerSpecification()); count = customerManager.GetCustomerCount(new CustomerRegistrationYearSpecification(2017));
現(xiàn)在,我們可以優(yōu)化 CustomerManager 在數(shù)據(jù)庫中應(yīng)用過濾器:
public class CustomerManager { private readonly IRepository<Customer> _customerRepository; public CustomerManager(IRepository<Customer> customerRepository) { _customerRepository = customerRepository; } public int GetCustomerCount(ISpecification<Customer> spec) { return _customerRepository.Count(spec.ToExpression()); } }
這很簡單 我們可以將任何規(guī)范傳遞給存儲(chǔ)庫,因?yàn)?nbsp;存儲(chǔ)庫可以使用表達(dá)式作為過濾器。在此示例中,CustomerManager是不必要的,因?yàn)槲覀兛梢灾苯邮褂镁哂幸?guī)范的存儲(chǔ)庫來查詢數(shù)據(jù)庫。但是認(rèn)為我們想對一些客戶執(zhí)行業(yè)務(wù)操作。在這種情況下,我們可以使用具有域服務(wù)的規(guī)范來指定客戶進(jìn)行工作。
規(guī)格一個(gè)強(qiáng)大的功能是,它們可組合使用 AND,OR,不和ANDNOT擴(kuò)展方法。例:
var count = customerManager.GetCustomerCount(new PremiumCustomerSpecification().And(new CustomerRegistrationYearSpecification(2017)));
我們甚至可以從現(xiàn)有規(guī)范中創(chuàng)建一個(gè)新的規(guī)范類:
public class NewPremiumCustomersSpecification : AndSpecification<Customer>{ public NewPremiumCustomersSpecification() : base(new PremiumCustomerSpecification(), new CustomerRegistrationYearSpecification(2017)) { } }
規(guī)范是Specification 類的一個(gè)子類,只有在兩個(gè)規(guī)范都滿足的時(shí)候才能滿足。那么我們可以像其他規(guī)格一樣使用NewPremiumCustomersSpecification:
var count = customerManager.GetCustomerCount(new NewPremiumCustomersSpecification());
雖然規(guī)范模式比C#lambda表達(dá)式更早,但它通常與表達(dá)式進(jìn)行比較。一些開發(fā)者可能會(huì)認(rèn)為它不再需要,我們可以直接將表達(dá)式傳遞到存儲(chǔ)庫或域服務(wù),如下所示:
var count = _customerRepository.Count(c => c.Balance > 100000 && c.CreationYear == 2017);
由于ABP的存儲(chǔ)庫支持expessions,這是完全有效的用法。您不必在應(yīng)用程序中定義或使用任何規(guī)范,您可以使用表達(dá)式。那么說明什么呢?為什么和何時(shí)應(yīng)該考慮使用它們?
使用規(guī)格的一些好處:
Reusabe:認(rèn)為您需要在您的代碼庫中的許多地方使用PremiumCustomer過濾器。如果您使用表達(dá)式而不是創(chuàng)建規(guī)范,如果您以后更改“高級(jí)客戶”定義(例如,要將最終余額從100,000美元更改為25萬美元,并添加另一個(gè)條件,以成為3歲以上的客戶),會(huì)發(fā)生什么。如果您使用規(guī)范,您只需更改單個(gè)類。如果您使用(復(fù)制/粘貼)相同的表達(dá)式,則需要更改它們。
可組合:您可以將多個(gè)規(guī)格來創(chuàng)建新的規(guī)范。這是另一種可重用性。
命名:PremiumCustomerSpecification更好地解釋了意圖,而不是復(fù)雜的表達(dá)。因此,如果您的業(yè)務(wù)有意義的表達(dá)式,請考慮使用規(guī)范。
可測試:一個(gè)規(guī)范是單獨(dú)(和容易)可測試的對象。
非業(yè)務(wù)表達(dá)式:您可以考慮不使用非業(yè)務(wù)相關(guān)表達(dá)式和操作的規(guī)范。
報(bào)告:如果你只是創(chuàng)建一個(gè)報(bào)表,不要?jiǎng)?chuàng)建規(guī)范,而是直接使用IQueryable。實(shí)際上,您甚至可以使用簡單的SQL,Views或其他工具進(jìn)行報(bào)告。DDD不關(guān)心報(bào)告,并且從性能的角度來看,底層數(shù)據(jù)存儲(chǔ)的查詢優(yōu)勢可能很重要。
當(dāng)前名稱:規(guī)范模式-------FromABPDocument
轉(zhuǎn)載來于:http://www.rwnh.cn/article38/jepipp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化、網(wǎng)站收錄、定制開發(fā)、建站公司、動(dòng)態(tài)網(wǎng)站、微信小程序
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)