新聞中心
這里將要講述的是怎樣用C#中的Specification模式實(shí)現(xiàn)可定制的業(yè)務(wù)邏輯,也就是避免傳統(tǒng)where語(yǔ)句的局限性,在一定程度上是有其價(jià)值的。

今天有朋友在問(wèn)了我這么一個(gè)問(wèn)題:怎么實(shí)現(xiàn)OrWhere的功能?我猜測(cè),他的意思是要實(shí)現(xiàn)這樣的功能:
- static IEnumerable
MorePredicate(IEnumerable source) - {
- return source.OrWhere(i => i > 0); // 或所有的正數(shù)
- }
- static void Main(string[] args)
- {
- var array = Enumerable.Range(-5, 10).ToArray();
- var odd = array.Where(i => i % 2 != 0); // 排除所有偶數(shù)
- var oddOrPositive = MorePredicate(odd);
- foreach (var i in oddOrPositive)
- {
- Console.WriteLine(i);
- }
- }
以上代碼應(yīng)該輸出-5,-3,-1,1,2,3,4。但顯然,這段代碼是無(wú)法編譯通過(guò),無(wú)法通過(guò)補(bǔ)充類庫(kù)來(lái)實(shí)現(xiàn)的。因?yàn)樵贛ain方法中的Where過(guò)后,已經(jīng)排除了所有的偶數(shù),于是在接下來(lái)的代碼中是無(wú)法從新的序列中再次恢復(fù)元素的。
不過(guò)這個(gè)要求讓我想起了Specification模式。Specification模式的作用是構(gòu)建可以自由組裝的業(yè)務(wù)邏輯元素。Specification類有一個(gè)IsSatisifiedBy函數(shù),用于校驗(yàn)?zāi)硞€(gè)對(duì)象是否滿足該Specification所表示的條件。多個(gè)Specification對(duì)象可以組裝起來(lái),并生成新Specification對(duì)象,這便可以形成高度可定制的業(yè)務(wù)邏輯。例如,我們可以使用依賴注入(控制反轉(zhuǎn))的方式來(lái)配置這個(gè)業(yè)務(wù)邏輯,以此保證系統(tǒng)的靈活性。
如果您點(diǎn)開(kāi)上面那個(gè)Wikipedia的鏈接,就會(huì)發(fā)現(xiàn)這段描述大約是一個(gè)英譯中的練習(xí)。抄完了“定義”,再來(lái)看看同樣引自Wikipedia的UML圖:
一般來(lái)說(shuō),Specification模式則意味著實(shí)現(xiàn)這樣一個(gè)接口:
- public interface ISpecification
- {
- bool IsSatisfiedBy(T candidate);
- ISpecification And(ISpecification other);
- ISpecification Or(ISpecification other);
- ISpecification Not();
- }
實(shí)現(xiàn)了ISpecification的對(duì)象則意味著是一個(gè)Specification,它可以通過(guò)與其他Specification對(duì)象的And,Or或?qū)ψ陨淼娜》磥?lái)生成新的邏輯。為了方便這些“組合邏輯”的開(kāi)發(fā),我們還會(huì)準(zhǔn)備一個(gè)抽象的CompositeSpecification類:
- public abstract class CompositeSpecification : ISpecification
- {
- public abstract bool IsSatisfiedBy(T candidate);
- public ISpecification And(ISpecification other)
- {
- return new AndSpecification(this, other);
- }
- public ISpecification Or(ISpecification other)
- {
- return new OrSpecification(this, other);
- }
- public ISpecification Not()
- {
- return new NotSpecification(this);
- }
- }
CompositeSpecification提供了構(gòu)建復(fù)合Specification的基礎(chǔ)邏輯,它提供了And、Or和Not方法的實(shí)現(xiàn),讓其他Specification類只需要專注于IsSatisfiedBy方法的實(shí)現(xiàn)即可。例如,以下便是三種邏輯組合的具體實(shí)現(xiàn):
- public class AndSpecification : CompositeSpecification
- {
- private ISpecification m_one;
- private ISpecification m_other;
- public AndSpecification(ISpecification x, ISpecification y)
- {
- m_one = x;
- m_other = y;
- }
- public override bool IsSatisfiedBy(T candidate)
- {
- return m_one.IsSatisfiedBy(candidate) && m_other.IsSatisfiedBy(candidate);
- }
- }
- public class OrSpecification : CompositeSpecification
- {
- private ISpecification m_one;
- private ISpecification m_other;
- public OrSpecification(ISpecification x, ISpecification y)
- {
- m_one = x;
- m_other = y;
- }
- public override bool IsSatisfiedBy(T candidate)
- {
- return m_one.IsSatisfiedBy(candidate) || m_other.IsSatisfiedBy(candidate);
- }
- }
- public class NotSpecification : CompositeSpecification
- {
- private ISpecification m_wrapped;
- public NotSpecification(ISpecification x)
- {
- m_wrapped = x;
- }
- public override bool IsSatisfiedBy(T candidate)
- {
- return !m_wrapped.IsSatisfiedBy(candidate);
- }
- }
于是,我們便可以使用Specification模式來(lái)處理剛才那位朋友的問(wèn)題。例如,首先他需要排除所有的偶數(shù),那么我們不妨實(shí)現(xiàn)一個(gè)OddSpecification:
- public class OddSpecification : CompositeSpecification
- {
- public override bool IsSatisfiedBy(int candidate)
- {
- return candidate % 2 != 0;
- }
- }
自然,還有用于獲得所有正數(shù)的Specification類:
- public class PositiveSpecification : CompositeSpecification
- {
- public override bool IsSatisfiedBy(int candidate)
- {
- return candidate > 0;
- }
- }
于是在使用時(shí),我們會(huì)將其通過(guò)Or方法組合起來(lái):
- static ISpecification MorePredicate(ISpecification original)
- {
- return original.Or(new PositiveSpecification());
- }
- static void Main(string[] args)
- {
- var array = Enumerable.Range(-5, 10).ToArray();
- var oddSpec = new OddSpecification();
- var oddAndPositiveSpec = MorePredicate(oddSpec);
- foreach (var item in array.Where(i => oddAndPositiveSpec.IsSatisfiedBy(i)))
- {
- Console.WriteLine(item);
- }
- }
但是,您覺(jué)得這個(gè)做法怎么樣?我覺(jué)得過(guò)于殺雞用牛刀,高射炮打蚊子了。Specification模式雖然常用,但是用在這里太重量級(jí)了。如果我們?yōu)槊恳粋€(gè)函數(shù)都補(bǔ)充一個(gè)Specification類,至少會(huì)讓我感到厭倦。
以上的代碼其實(shí)轉(zhuǎn)載自Wikipedia詞條,不過(guò)我修改了一些命名,以及改寫(xiě)成泛型版本。我們有理由推測(cè),Wikipedia上是非常舊的內(nèi)容,很可能是在C#只是1.0版本的時(shí)候編寫(xiě)的代碼(或者說(shuō)它為了“兼容”Java那種語(yǔ)言的實(shí)現(xiàn)方式)。那么在實(shí)際開(kāi)發(fā)過(guò)程中,我們又該如何利用C#如今的強(qiáng)大特性來(lái)實(shí)現(xiàn)出更容易使用,甚至是更為“輕量級(jí)”的Specification模式呢?
此外,剛才又收到那位朋友的消息,他其實(shí)是想在使用LINQ to SQL時(shí)實(shí)現(xiàn)“可擴(kuò)展的邏輯”。那么,對(duì)于他說(shuō)的情況,我們又該如何應(yīng)對(duì)呢?
新聞標(biāo)題:C#中用Specification模式實(shí)現(xiàn)可定制的業(yè)務(wù)邏輯
標(biāo)題路徑:http://www.dlmjj.cn/article/cccdics.html


咨詢
建站咨詢
