Specification pattern has emerged out of “Domain Driven Design” phenomenon. It is first identified and articulated here by Eric Evans and Martin Fowler. Specification Pattern is based on method chaining technique and beautifully uses fluent interfaces. In method chaining, we get desired results by operating over the object through series of methods which returns the same type of object. One of the examples of method chaining is given below,
var Television = televisionFactory.New() .SetColor("blue") .SetHeight(1) .SetLength(2);
With the help of specification pattern, business logic or business rules management inside the application can be simplified and code becomes more readable and you can remove those ugly “if else” ladders. Specification immensely helps out to refactor the existing code so as to consolidate the business rules of the system. More benefits of specifications are; you can change the business rule either in terms of hard values or also in terms of business rule composition itself.
Let’s take a following code sample inside order class, which is pretty common use
public bool HasDiscountWithoutSpecification() { if (SKUs >= 10000 && ModeOfPayment == PaymentMode.CashOnDelivery && ShippingAddress.Country == "USA" && OrderAmount >= 50000 && IsTaxApplicable == false) { AllowDiscount = true; } return AllowDiscount; }
With Specification pattern we can turn above code into something like
public bool HasDiscountWithSpecification() { var spec = new DiscountSpecification(); return spec.IsSatisfiedBy(this); }
With Specification pattern while we are dealing with flow of information business rule complexity is abstracted and code looks pretty simple.
If you explore the code provided with this post (source code pointer at the end of the post) further, you will see the beauty of construction of specification named “DiscountSpecification”. Discount Specification has method called SatisfiedBy method which utilizes other specifications and builds the business rule whether on specified order, discount is applicable or not. Since Discount specification is built on other specifications it’s a “Composite specification”. Sometimes, this terminology is used to indicate the construction of specifications.
Here is the code for IsSatisfiedBy method.
public override bool IsSatisfiedBy(Order candidate) { return domesticOrderSpec .And(highValueSpec) .And(highStockSpec) .And(taxableSpec.Not()) .IsSatisfiedBy(candidate); }
The beauty above code is, even in future, if business rules for discount applicability changes, we just need to change the IsSatisfiedBy method in DiscountSpecification and we are done. For e.g. If business has removed Stock requirements of having 1000 SKUs. Then we just need to remove the highstockSpec AND operation”. So the code after High stock rule is removed will be simply
public override bool IsSatisfiedBy(Order candidate) { return domesticOrderSpec .And(highValueSpec) //.And(highStockSpec) .And(taxableSpec.Not()) .IsSatisfiedBy(candidate); }
And this business rule change will be reflected across the application. Now, consider that business changed the rule and now discount will be only given to orders having order total more than 50000 USD. Then, we just need to reflect this change inside our HighValueSpecification class.
In similar fashion, we can also add new Specifications to satisfy the new business rules.
The useful scenarios where specification pattern can be used inside the application are as follows:
You can find the Code sample for this post on github here. I have not included tests with this sample. The code sample also contains a small specification framework that you can reuse. Please note that, this code is not a production code and posted on github for the explanatory purpose.