![]() |
Development Lifecycle »
Design and Architecture »
Design Patterns
Intermediate
License: The Code Project Open License (CPOL)
Using the Specification Design PatternBy daltonrThe final part of a four part series of articles on the Specification Design Pattern. |
VB 8.0, VB 9.0.NET 2.0, .NET 3.0, .NET 3.5, Architect, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
This is the third in a series of four articles discussing the Specification Design Pattern and how to implement it using VB.NET.
The Specification Design Pattern was created by Eric Evans. He provides a description of the pattern in his book, 'Domain Driven Design'. This series of articles shows how to implement the pattern using VB.NET.
The attached sample project includes Unit Tests in the GenericTests.vb file. These tests illustrate how to use the Generic Specification. The project uses NUnit for Unit Testing. If you do not have NUnit installed, you should remove GenericTests.vb from the project and remove the reference to nunit.framework.
In the third article in this series, we created a generic base Specification class which could be reused and inherited from to create specifications for any kind of object.
In this final article, we'll create a ContainerSpecification which uses the Specification class to work with the Container object that we coded in the earlier articles. Our ContainerSpecification is declared as follows:
Public Class ContainerSpecification
Inherits Specification(Of Container)
You'll recall that when we declared the Specification class in Part III, we used the (Of T) notation to indicate that a type would be passed in when instances are created. By specifying (Of Container), we indicate to the Specification class that T means Container.
In Part II, we saw that the features of a container can be defined using a flags enum. Since a ContainerSpecification represents a required feature, we need a variable within the specification to store it.
Private _requiredFeature As ContainerFeature
The Constructor is very simple, it requires the desired feature as a parameter and sets the member variable.
Public Sub New(ByVal requiredFeature As ContainerFeature)
_requiredFeature = requiredFeature
End Sub
We need to override the SpecificationRule function. This function is defined in the base Specification class, but each specification must implement its own logic. In this case, the logic is simple to check if a passed in Container (the candidate object) has the required feature as defined by the specification.
Protected Overrides Function SpecificationRule(ByVal candidate As Container) As Boolean
Return CType(candidate.Features And _requiredFeature, Boolean)
End Function
Finally, to make it possible to combine ContainerSpecifications using logical operators like AND, OR, and NOT, we need to overload those operators. These overloaded functions make use of the An, dOperatorOrOperator, and NotOperator functions in the base Specification class.
Public Overloads Shared Operator And(ByVal a As ContainerSpecification, _
ByVal b As ContainerSpecification) As ContainerSpecification
Return CType(Specification(Of Container).AndOperator(a, b), ContainerSpecification)
End Operator
Public Overloads Shared Operator Or(ByVal a As ContainerSpecification, _
ByVal b As ContainerSpecification) As ContainerSpecification
Return CType(Specification(Of Container).OrOperator(a, b), ContainerSpecification)
End Operator
Public Overloads Shared Operator Not(ByVal a As ContainerSpecification) _
As ContainerSpecification
Return CType(Specification(Of Container).NotOperator(a), ContainerSpecification)
End Operator
That's all there is to creating a specification. Most of the heavy lifting is now done in the base specification class. We no longer have to worry about how the AND, OR, and NOT operators are actually implemented, or how complex trees of specifications are represented.
The attached sample projects include Unit Tests that demonstrate how to use the specifications that we produce. The following are a few examples:
Dim drum As New Drum("Acid", 500, New ContainerSpecification(ContainerFeature.Armored))
Dim container As New Container(10000, ContainerFeature.Armored)
Assert.IsTrue(drum.RequiredContainer.IsSatisfiedBy(container))
We declare a drum which holds a quantity of 500 of Acid, and requires an Armored container. We then declare a Container that is Armored.
The drum has a RequiredContainer property which is a Specification; its IsSatisfiedBy method checks our container and indicates that it is OK for the drum.
The next example shows how we can define a composite specification by combining existing specifications. We start with an Armored Specification and a Ventilated Specification. The AND and OR operators allow us to define new specifications that represent either Armored OR Ventilated, or both Armored AND Ventilated.
' Create Specifications
Dim armoredSpec As New ContainerSpecification(ContainerFeature.Armored)
Dim ventilatedSpec As New ContainerSpecification(ContainerFeature.Ventilated)
Dim either As ContainerSpecification = armoredSpec Or ventilatedSpec
Dim both As ContainerSpecification = armoredSpec And ventilatedSpec
In the past, either and both would have been new separate classes. Here, they are just variables that combine the behaviours of existing classes. We can use them just like any Specification.
For example, we can pass a composite specification to the constructor of a Drum.
' Create Drums, using Specifications to define acceptable containers
Dim uraniumDrum As New Drum("Uranium", 5000, either)
Dim tntDrum As New Drum("TNT", 5000, both)
Over the course of this four part series, we have learned about when and why to use Specifications. We have implemented a simple Specification, and we have created a generic base specification class that can be reused.
The sample projects that accompany this series should provide you with additional insight into how this useful Design Pattern works.
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 5 Apr 2009 Editor: Smitha Vijayan |
Copyright 2009 by daltonr Everything else Copyright © CodeProject, 1999-2009 Web10 | Advertise on the Code Project |