2014-10-18 26 views
0

我需要複雜多類型<TLeft,TRight>)規範,比如:規格模式:多類型複合規格

public class AndSopecification<TLeft,TRight> 
{ 

    public AndSpecification(ISpecification<TLeft> leftSide, ISpecification<TRight> rightSide) 
    { 
    } 
    . 
    . 
    . 
} 

但是,所有規格的例子,我看實現單一類型<T>),如:

public sealed class AndSpecification<T> : CompositeSpecification<T> 
{ 
    public AndSpecification(ISpecification<T> leftSide, ISpecification<T> rightSide) 
    {    
    } 
    . 
    . 
    . 
} 

是否有任何問題,如果我創建像這樣複雜的規格:

new AndSpecification<Foo,Bar>(new FooSpecification(),new BarSpecification()).SatisfiedBy(); 

因此,我可以在不同的情況下相互重複使用所有規格,然後我可以擁有單一的唯一過程點,這些點可以是更復雜規格樹的組成單元。

但我找不到這樣的實現。

我在一條正確的道路上嗎?

編輯:

我翻譯哪些客戶每次使用的條件語句,爲specification,到處重用他們的客戶重用句子

(在每一個相關logicquery predicatebusiness rule validation。 ..,我認爲這些specifications自然是相同的在這些情況下)

而且作爲客戶,我創建composite specifications,

但我有不同的基礎設施訪問他們的情況下,每一個(query predicatebusiness rule validation,...)

+1

你確定你需要它嗎?將一個特定的用例標準封裝在一個對象中,而不是編寫_n_通用標準,這是非常簡單和有效的。 – MikeSW 2014-10-18 13:57:02

+0

@MikeSW:爲什麼我應該重寫說'IsLogedInUserAdminSpecification'應該根據每個業務邏輯(以及在我定義的每個'Specification中)檢查? – Mohsen 2014-10-19 05:07:13

+1

該檢查不應該是你的域的一部分,它是基礎設施的一部分。 – MikeSW 2014-10-19 14:06:56

回答

1

我有一種實現在那裏我可以做到這使得我,因爲我看到重用規格如下適合。

public class Composite 
{ 
    public Foo _foo; 
    public Bar _bar; 
} 

var fooSpec = new Specification<Foo>(f => f.IsActive); 
var barSpec = new Specification<Bar>(f => f.IsActive); 

var comSpec = new Specification<TheComposite>(c => true); 

comSpec = comSpec.And(c => c.Foo, fooSpec) 
       .And(c => c.Bar, barSpec); 

如果這是你在找什麼,這裏是我是如何做到的。

public class Specification<TEntity> 
{ 
    private readonly Expression<Func<TEntity, bool>> _expression; 

    public static Specification<TEntity> Create<TNestedEntity>(Expression<Func<TEntity, TNestedEntity>> propertyExpression, ISpecification<TNestedEntity> spec) 
    { 
     var replacer = new ParameterReplaceVisitor(spec.EvalExpression.Parameters.First(), propertyExpression.Body); 
     var newExpression = replacer.Visit(spec.EvalExpression.Body); 
     var exp = Expression.Lambda<Func<TEntity, bool>>(newExpression, propertyExpression.Parameters); 
     return new Specification<TEntity>(exp); 
    } 

    public virtual bool IsSatisfiedBy(TEntity e) 
    { 
     return EvalFunc(e); 
    } 

    public ISpecification<TEntity> And(ISpecification<TEntity> other) 
    { 
     return new Specification<TEntity>(EvalExpression.And(other.EvalExpression)); 
    } 

    public ISpecification<TEntity> And<TNestedEntity>(Expression<Func<TEntity, TNestedEntity>> property, ISpecification<TNestedEntity> spec) 
    { 
     return And(Create(property, spec)); 
    } 
    ... 
} 

private class ParameterReplaceVisitor : ExpressionVisitor 
{ 
    private readonly Expression _replacementExpression; 
    private readonly ParameterExpression _parameter; 

    public ParameterReplaceVisitor(ParameterExpression parameter, Expression replacementExpression) 
    { 
     _parameter = parameter; 
     _replacementExpression = replacementExpression; 
    } 

    protected override Expression VisitParameter(ParameterExpression node) 
    { 
     // If the node is the parameter we are trying to replace, 
     // return the expression that should replace it. 
     return (node == _parameter) ? _replacementExpression : node; 
    } 
} 

ExpressionVisitor是System.Linq.Expressions

的一部分

當然,你也可以實現或()

我希望這是你在找什麼,這有助於。

+0

非常有用。爲什麼這是我見過的整個網絡上唯一的地方!?似乎很明顯,應該能夠從主要類型屬性的規範中編寫規範。 – Felix 2015-12-03 02:13:03

+0

將請求添加到netfx擴展包... https://github.com/netfx/extensions/pull/3 – Felix 2015-12-07 02:45:59

1

創建與特定類型的對象無關的規範會影響目標。來自埃裏克埃文斯:「一個規格是一個謂詞,決定一個對象是否滿足某些標準。」所以你總是必須針對一個實例來評估一個規範。複合規範用於組合與同一類對象相關的規範。

規範與業務規則不是一回事。你可以有一個業務規則使用多個規範。例如:如果顧客想要購買一輛大轎車,那麼他需要在他的銀行賬戶中存入一些錢。

var bigCar = new Specification<Car>(car => car.Size == "big"); 
var accountHasMoney = new Specification<Account>(account => account.Balance > 0); 

// This rule takes a car and an account 
public bool CanBuyBigCar(Car car, Account account) { 
    return bigCar.IsSatisfiedBy(car) && accountHasMoney.IsSatisfiedBy(account) 
} 

如果你想重新使用這些規範在您的SQL查詢,那麼你可以使用隱式的運營商,使其更容易與IQueryables使用它:

public static implicit operator Expression<Func<T, bool>>(Specification<T> specification) 
{ 
    return specification.Expression; 
} 

public static implicit operator Func<T, bool>(Specification<T> specification) 
{ 
    return specification.IsSatisfiedBy; 
} 

現在的規格可直接查詢所有IQueryables,IEnumerables和所有其他種類的集合。

你可以在這裏找到一個隨時可以使用的實現:https://github.com/jnicolau/NSpecifications/tree/master/Nspecifications