十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
规范模式是一种特定的软件设计模式,通过使用布尔逻辑 (维基百科)将业务规则链接在一起,可以重新组合业务规则。
让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:域名申请、雅安服务器托管、营销软件、网站建设、隰县网站维护、网站推广。在实际中,它主要用于 为实体或其他业务对象定义可重用的过滤器。
在本节中,我们将看到需要规格模式。本节是通用的,与ABP的实现无关。
假设您有一种服务方法来计算客户的总数,如下所示:
public class CustomerManager { public int GetCustomerCount() { // TODO ... return 0 ; } }
您可能希望通过过滤器获得客户数量。例如,您可能会有高级客户(其余额超过10万美元),或者您可能想要通过 注册年度过滤客户。然后,您可以创建其他方法,如GetPremiumCustomerCount(), GetCustomerCountRegisteredInYear(int year), GetPremiumCustomerCountRegisteredInYear(int year)等。由于您有更多的标准,因此无法为每种可能性创建组合。
这个问题的一个解决方案是规范模式。我们可以创建一个获取参数作为过滤器的方法:
public class CustomerManager { private readonly IRepository_customerRepository; public CustomerManager(IRepository customerRepository) { _customerRepository = customerRepository; } public int GetCustomerCount(ISpecification spec) { var customers = _customerRepository.GetAllList(); var customerCount = 0; foreach (var customer in customers) { if (spec.IsSatisfiedBy(customer)) { customerCount++; } } return customerCount; } }
因此,我们可以获得任何对象作为实现 ISpecification
public interface ISpecification{ bool IsSatisfiedBy(T obj); }
我们可以与客户一起致电IsSatisfiedBy,以测试该客户是否有意。因此,我们可以使用相同的GetCustomerCount与不同的过滤器,而不改变方法本身。
虽然这个解决方案在理论上是相当不错的,但应该改进,以更好地在C#中工作。例如,它是没有效率得到所有客户提供从数据库来检查它们是否满足给定的规格/条件。在下一节中,我们将看到ABP的实现,克服了这个问题。
ABP定义了ISpecification界面,如下所示:
public interface ISpecification{ bool IsSatisfiedBy(T obj); Expression > ToExpression(); }
添加ToExpression()方法,该方法返回一个表达式,并用于更好地与IQueryable和 Expression树的集成。因此,我们可以轻松地将规范传递给存储库,以在数据库级别应用过滤器。
我们通常从规范
//Customers with $100,000+ balance are assumed as PREMIUM customers.public class PremiumCustomerSpecification : Specification{ public override Expression > ToExpression() { return (customer) => (customer.Balance >= 100000); } }//A parametric specification example.public class CustomerRegistrationYearSpecification : Specification { public int Year { get; } public CustomerRegistrationYearSpecification(int year) { Year = year; } public override Expression > ToExpression() { return (customer) => (customer.CreationYear == Year); } }
如你所见,我们只是实现了简单的lambda表达式 来定义规范。让我们使用这些规格来获得客户数量:
count = customerManager.GetCustomerCount(new PremiumCustomerSpecification()); count = customerManager.GetCustomerCount(new CustomerRegistrationYearSpecification(2017));
现在,我们可以优化 CustomerManager 在数据库中应用过滤器:
public class CustomerManager { private readonly IRepository_customerRepository; public CustomerManager(IRepository customerRepository) { _customerRepository = customerRepository; } public int GetCustomerCount(ISpecification spec) { return _customerRepository.Count(spec.ToExpression()); } }
这很简单 我们可以将任何规范传递给存储库,因为 存储库可以使用表达式作为过滤器。在此示例中,CustomerManager是不必要的,因为我们可以直接使用具有规范的存储库来查询数据库。但是认为我们想对一些客户执行业务操作。在这种情况下,我们可以使用具有域服务的规范来指定客户进行工作。
规格一个强大的功能是,它们可组合使用 AND,OR,不和ANDNOT扩展方法。例:
var count = customerManager.GetCustomerCount(new PremiumCustomerSpecification().And(new CustomerRegistrationYearSpecification(2017)));
我们甚至可以从现有规范中创建一个新的规范类:
public class NewPremiumCustomersSpecification : AndSpecification{ public NewPremiumCustomersSpecification() : base(new PremiumCustomerSpecification(), new CustomerRegistrationYearSpecification(2017)) { } }
规范是Specification 类的一个子类,只有在两个规范都满足的时候才能满足。那么我们可以像其他规格一样使用NewPremiumCustomersSpecification:
var count = customerManager.GetCustomerCount(new NewPremiumCustomersSpecification());
虽然规范模式比C#lambda表达式更早,但它通常与表达式进行比较。一些开发者可能会认为它不再需要,我们可以直接将表达式传递到存储库或域服务,如下所示:
var count = _customerRepository.Count(c => c.Balance > 100000 && c.CreationYear == 2017);
由于ABP的存储库支持expessions,这是完全有效的用法。您不必在应用程序中定义或使用任何规范,您可以使用表达式。那么说明什么呢?为什么和何时应该考虑使用它们?
使用规格的一些好处:
Reusabe:认为您需要在您的代码库中的许多地方使用PremiumCustomer过滤器。如果您使用表达式而不是创建规范,如果您以后更改“高级客户”定义(例如,要将最终余额从100,000美元更改为25万美元,并添加另一个条件,以成为3岁以上的客户),会发生什么。如果您使用规范,您只需更改单个类。如果您使用(复制/粘贴)相同的表达式,则需要更改它们。
可组合:您可以将多个规格来创建新的规范。这是另一种可重用性。
命名:PremiumCustomerSpecification更好地解释了意图,而不是复杂的表达。因此,如果您的业务有意义的表达式,请考虑使用规范。
可测试:一个规范是单独(和容易)可测试的对象。
非业务表达式:您可以考虑不使用非业务相关表达式和操作的规范。
报告:如果你只是创建一个报表,不要创建规范,而是直接使用IQueryable。实际上,您甚至可以使用简单的SQL,Views或其他工具进行报告。DDD不关心报告,并且从性能的角度来看,底层数据存储的查询优势可能很重要。
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。