首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >规格模式:多类型复合规格

规格模式:多类型复合规格
EN

Stack Overflow用户
提问于 2014-10-18 12:27:19
回答 3查看 555关注 0票数 0

我需要复杂的多类型 (<TLeft,TRight>)规范,如:

代码语言:javascript
复制
public class AndSopecification<TLeft,TRight>
{

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

但是,我看到的所有规范示例都实现了单类型 (<T>),如:

代码语言:javascript
复制
public sealed class AndSpecification<T> : CompositeSpecification<T>
{
    public AndSpecification(ISpecification<T> leftSide, ISpecification<T> rightSide)
    {            
    }
    .
    .
    .
}

如果我创建复杂的规范(如:

代码语言:javascript
复制
new AndSpecification<Foo,Bar>(new FooSpecification(),new BarSpecification()).SatisfiedBy();

因此,我可以在不同的情况下重用彼此内部的所有规范,然后我可以有一个唯一的流程点,它们可以是更复杂的规范树的组合单元。

但我找不到这样的实现。

我在正确的道路上吗?

编辑:

我正在将客户使用的每一个条件句翻译成一个specification,并在任何地方重用它们--客户重复使用这个句子

(在所有相关的logicquery predicatebusiness rule validation、.中,我认为这些specifications在每种情况下都是自然相同的)

和客户一样,我创建了composite specifications

但在每一种情况下,我都使用不同的基础设施访问它们(query predicatebusiness rule validation,.)

EN

回答 3

Stack Overflow用户

发布于 2015-03-26 19:14:47

我有一个实现,在这里我可以执行以下操作,它使我能够根据自己的需要重用规范。

代码语言:javascript
复制
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); 

如果这就是你要找的,我就是这么做的。

代码语言:javascript
复制
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的一部分

当然,您也可以实现或()

我希望这是你正在寻找的,这是有帮助的。

票数 1
EN

Stack Overflow用户

发布于 2016-01-13 11:46:50

创建一个与特定对象类型无关的规范会违背目的。Evans说:“规范是一个谓词,它决定一个对象是否满足某些条件。因此,您总是必须根据实例对规范进行评估。复合规范用于组合与同一类对象相关的规范。

规范与业务规则不是一回事。您可以有一个业务规则--使用多个规范。例句:如果顾客想买一辆大轿车,那么他需要在他的银行账户里存一些钱。

代码语言:javascript
复制
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中使用:

代码语言:javascript
复制
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

票数 1
EN

Stack Overflow用户

发布于 2019-10-25 13:18:24

我觉得搞不懂为什么您需要在多个类型上指定。但你没有理由不能这么做。从技术上讲,您可以使用元组规范。

代码语言:javascript
复制
var spec = new Spec<(int num, string text)>(x => x.num == 1 && x.text == "a");
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26439718

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档