A KISS approach for specification pattern
C# CSS Other
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
.nuget Trying Travis CI. Sep 23, 2013
KissSpecifications.Samples.Domain
KissSpecifications.Samples.Mvc
KissSpecifications.UnitTests
KissSpecifications
nuget
.gitignore
.travis.yml
KissSpecifications.FxCop
KissSpecifications.sln
KissSpecifications.sln.GhostDoc.xml
KissSpecifications.sln.vsdoc Using "Enabled NuGet Package Restore" Apr 17, 2013
KissSpecifications.vsmdi
Local.testsettings
README.md
TraceAndTestImpact.testsettings First version. Apr 17, 2013

README.md

KissSpecifications

A KISS approach for specification pattern. http://en.wikipedia.org/wiki/Specification_pattern

Setup

NuGet

PM> Install-Package KissSpecifications

Features

  • ISpecification : interface to define any kind of specification
  • SpecificationBase : base class to easy create new specifications
  • SpecificationService : Service class with features to validate specifications
  • SpecificationGroups : attribute to define groups for a specification
  • Commons specifications
    • MustHaveNullOrDefaultPropertySpecification
    • MustNotBeNullSpecification
    • MustNotHaveEmptyPropertyTextSpecification
    • MustNotHaveNullOrDefaultPropertySpecification
  • Globalization
    • IGlobalizationResolver interface to define any kind of globalization for commons specifications

Using

  • Create your specification classes:
public class CustomerMustHaveValidNameSpecification : SpecificationBase<string>
{

		#region Constants
		public const int MinCustomerName = 5;
		public const int MaxCustomerName = 30;
		#endregion

		#region Methods
		public override bool IsSatisfiedBy(string target)
		{
			if (String.IsNullOrWhiteSpace(target))
			{
				NotSatisfiedReason = "Customer name should be specified.";
				return false;
			}

			if (target.Length < MinCustomerName)
			{
				NotSatisfiedReason = String.Format(CultureInfo.CurrentUICulture, "The minimum length for customer name is {0} chars.", MinCustomerName);
				return false;
			}

			if (target.Length > MaxCustomerName)
			{
				NotSatisfiedReason = String.Format(CultureInfo.CurrentUICulture, "The maximum length for customer name is {0} chars.", MaxCustomerName);
				return false;
			}

			return true;
		}
		#endregion
}
  • Call the SpecificationService on your Domain method:
public static class CustomerService
{

	public static void CreateCustomer(Customer customer)
	{
		SpecificationService.ThrowIfAnySpecificationIsNotSatisfiedBy(customer, new CustomerCreationSpecification());

		// TODO: Logic to create customer...
	}
}

Create Groups of specification

Defining groups

You can use any object to declare a group key for your specification, but is always better to define constants or enumerators.

/// <summary>
/// Just a enum to define my specification groups.
/// </summary>
public enum SampleSpecificationGroup
{
	Save = 0,
	SendEmail = 1,
}


[SpecificationGroups (SampleSpecificationGroup.Save, "Sell")]
public class CustomerMustHaveNameSpecification : ISpecification<Customer>
{
	...
}

[SpecificationGroups (1, 5)]
public class CustomerMustHaveValidAccountSpecification : ISpecification<Customer>
{
	...
}

[SpecificationGroups (SampleSpecificationGroup.SendEmail)]
public class CustomerMustHaveEmailSpecification : ISpecification<Customer>
{
	...
}

[SpecificationGroups (Constants.AConstantValue, "Sell", 1)]
public class CustomerCanNotHaveDebitSpecification : ISpecification<Customer>
{
	...
}

Validate

  • Call the SpecificationService on your Domain method defining groups that you want to validate:
public static class CustomerService
{

	public static void CreateCustomer(Customer customer)
	{
		SpecificationService.ThrowIfAnySpecificationIsNotSatisfiedBy(customer, SampleSpecificationGroup.Save);

		// TODO: Logic to create customer...
	}
}

Best practices

Naming

Let everyone know exactly what you are trying to specify! Create meaningful names for your specification classes. It will keep your code readable and easy to maintain.

public static class CustomerService
{

	public static void CreateCustomer(Customer customer)
	{
		SpecificationService.ThrowIfAnySpecificationIsNotSatisfiedBy(
			customer, 
			new CustomerMustHaveNameSpecification(),
			new CustomerMustHaveValidAccountSpecification(),
			new CustomerMustHaveEmailSpecification(),
			new CustomerCanNotHaveDebitSpecification());

		// TODO: Logic to create customer...
	}
}

License

Licensed under the The MIT License (MIT). In others words, you can use this library for developement any kind of software: open source, commercial, proprietary and alien.

Change Log

  • 1.1.9 HelperSharp updated.
  • 1.1.8 Added MustExistsSpecification.
  • 1.1.7 Added MustHaveUniqueTextSpecification.
  • 1.1.6 Added specification groups feature.
  • 1.1.5 Added MustNotBeNullSpecification.
  • 1.1.4
    • KissSpecificationsConfig
    • IGlobalizationProvider
    • Commons specifications
      • MustHaveNullOrDefaultPropertySpecification
      • MustNotHaveEmptyPropertyTextSpecification
      • MustNotHaveNullOrDefaultPropertySpecification
  • 1.1.0 Added SpecificationService.ThrowIfAnySpecificationIsNotSatisfiedByAny.
  • 1.0.0 First version.