规范模式-------From ABP Document

发布时间:2020-07-06 16:51:26 作者:吴金瑞
来源:网络 阅读:397

    

介绍

规范模式是一种特定的软件设计模式,通过使用布尔逻辑 (维基百科)将业务规则链接在一起,可以重新组合业务规则

在实际中,它主要用于 为实体或其他业务对象定义可重用的过滤器

在本节中,我们将看到需要规格模式。本节是通用的,与ABP的实现无关。

假设您有一种服务方法来计算客户的总数,如下所示:

 规范模式-------From ABP Document

public  class CustomerManager
{    public  int  GetCustomerCount()
    {        // TODO ... 
        return  0 ;
    }
}

 规范模式-------From ABP Document

 

您可能希望通过过滤器获得客户数量。例如,您可能会有高级客户(其余额超过10万美元),或者您可能想要通过 注册年度过滤客户。然后,您可以创建其他方法,如GetPremiumCustomerCount() GetCustomerCountRegisteredInYear(int year) GetPremiumCustomerCountRegisteredInYear(int year)等。由于您有更多的标准,因此无法为每种可能性创建组合。

这个问题的一个解决方案是规范模式。我们可以创建一个获取参数作为过滤器的方法

 规范模式-------From ABP Document

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;
    }
}

 规范模式-------From ABP Document

 

因此,我们可以获得任何对象作为实现 ISpecification <Customer>接口的参数,定义如下:

public interface ISpecification<T>{    bool IsSatisfiedBy(T obj);
}

 

 

我们可以与客户一起致电IsSatisfiedBy,以测试该客户是否有意。因此,我们可以使用相同的GetCustomerCount与不同的过滤器,而不改变方法本身。

虽然这个解决方案在理论上是相当不错的,但应该改进,以更好地在C#中工作。例如,它是没有效率得到所有客户提供从数据库来检查它们是否满足给定的规格/条件。在下一节中,我们将看到ABP的实现,克服了这个问题。

创建规范类

ABP定义了ISpecification界面,如下所示:

 规范模式-------From ABP Document

public interface ISpecification<T>{    bool IsSatisfiedBy(T obj);

    Expression<Func<T, bool>> ToExpression();
}

 规范模式-------From ABP Document

 

 

添加ToExpression()方法,该方法返回一个表达式,并用于更好地与IQueryable和 Expression树的集成。因此,我们可以轻松地将规范传递给存储库,以在数据库级别应用过滤器。

我们通常从规范<T>类继承,而不是直接实现ISpecification <T>接口。规范类自动实现IsSatisfiedBy方法。所以,我们只需要定义ToExpression。我们来创建一些规范类:

 规范模式-------From ABP Document

//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);
    }
}

 规范模式-------From ABP Document

 

 

如你所见,我们只是实现了简单的lambda表达式 来定义规范。让我们使用这些规格来获得客户数量:

count = customerManager.GetCustomerCount(new PremiumCustomerSpecification());
count = customerManager.GetCustomerCount(new CustomerRegistrationYearSpecification(2017));

 

使用规范与存储库

现在,我们可以优化 CustomerManager 在数据库中应用过滤器

 规范模式-------From ABP Document

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());
    }
}

 规范模式-------From ABP Document

 

 

这很简单 我们可以将任何规范传递给存储库,因为 存储库可以使用表达式作为过滤器。在此示例中,CustomerManager是不必要的,因为我们可以直接使用具有规范的存储库来查询数据库。但是认为我们想对一些客户执行业务操作。在这种情况下,我们可以使用具有域服务的规范来指定客户进行工作。

撰写规格

规格一个强大的功能是,它们可组合使用 AND,OR,不ANDNOT扩展方法。例:

var count = customerManager.GetCustomerCount(new PremiumCustomerSpecification().And(new CustomerRegistrationYearSpecification(2017)));

 

 

我们甚至可以从现有规范中创建一个新的规范类:

 规范模式-------From ABP Document

public class NewPremiumCustomersSpecification : AndSpecification<Customer>{    public NewPremiumCustomersSpecification() 
        : base(new PremiumCustomerSpecification(), new CustomerRegistrationYearSpecification(2017))
    {
    }
}

 规范模式-------From ABP Document

 

 

规范Specification 类的一个子类,只有在两个规范都满足的时候才能满足。那么我们可以像其他规格一样使用NewPremiumCustomersSpecification:

var count = customerManager.GetCustomerCount(new NewPremiumCustomersSpecification());

 

 

讨论

虽然规范模式比C#lambda表达式更早,但它通常与表达式进行比较。一些开发者可能会认为它不再需要,我们可以直接将表达式传递到存储库或域服务,如下所示:

var count = _customerRepository.Count(c => c.Balance > 100000 && c.CreationYear == 2017);

 

 

由于ABP的存储库支持expessions,这是完全有效的用法。您不必在应用程序中定义或使用任何规范,您可以使用表达式。那么说明什么呢?为什么和何时应该考虑使用它们?

何时使用?

使用规格的一些好处:

何时不使用?



推荐阅读:
  1. CSS3中border-radius的使用方法
  2. 什么是软件设计中模块划分应遵循的准则

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

软件设计 过滤器 解决方案

上一篇:使用linux中whereis命令显示命令及相关文件的路径

下一篇:使用linux中ipstat命令实时显示Linux内核中iptables的工作状态

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》