Last week I went and checked out JP’s latest presentation on Generics at the Calgary .NET User Group, and as usual it was awesome! He’s definitely knee deep in C# 3.0, and was dropping lambda’s and extension methods like it was old news… Here’s some of the stuff I learned.
Extending the ISpecification interface via the use of Extension methods.
public static class SpecificationExtensions {
public static ISpecification< T > And< T >( this ISpecification< T > leftSide, ISpecification< T > rightSide ) {
return new AndSpecification< T >( leftSide, rightSide );
}
public static ISpecification< T > And< T >( this ISpecification< T > left, Predicate< T > criteriaToSatisfy ) {
return left.And( new Specification< T >( criteriaToSatisfy ) );
}
public static ISpecification< T > Or< T >( this ISpecification< T > leftSide, ISpecification< T > rightSide ) {
return new OrSpecification< T >( leftSide, rightSide );
}
public static ISpecification< T > Or< T >( this ISpecification< T > left, Predicate< T > criteriaToSatisfy ) {
return left.Or( new Specification< T >( criteriaToSatisfy ) );
}
private class AndSpecification< T > : ISpecification< T > {
public AndSpecification( ISpecification< T > leftCriteria, ISpecification< T > rightCriteria ) {
this.leftCriteria = leftCriteria;
this.rightCriteria = rightCriteria;
}
public bool IsSatisfiedBy( T item ) {
return leftCriteria.IsSatisfiedBy( item ) && rightCriteria.IsSatisfiedBy( item );
}
private ISpecification< T > leftCriteria;
private ISpecification< T > rightCriteria;
}
private class OrSpecification< T > : ISpecification< T > {
public OrSpecification( ISpecification< T > leftCriteria, ISpecification< T > rightCriteria ) {
this.leftCriteria = leftCriteria;
this.rightCriteria = rightCriteria;
}
public bool IsSatisfiedBy( T item ) {
return leftCriteria.IsSatisfiedBy( item ) || rightCriteria.IsSatisfiedBy( item );
}
private ISpecification< T > leftCriteria;
private ISpecification< T > rightCriteria;
}
}
By accepting a Predicate
public class SlipsRepository : ISlipsRepository {
public SlipsRepository( ISlipDataMapper mapper ) {
_mapper = mapper;
}
public IEnumerable< ISlip > AllAvailableSlips() {
return _mapper.AllSlips( ).Where( Is.NotLeased( ) );
}
public IEnumerable< ISlip > AllAvailableSlipsFor( IDock dockToFindSlipsOn ) {
return _mapper.AllSlips( ).Where( Is.NotLeased( ).And( Is.On( dockToFindSlipsOn ) ) );
}
private readonly ISlipDataMapper _mapper;
private static class Is {
public static ISpecification< ISlip > NotLeased() {
return new Specification< ISlip >( slip => !slip.IsLeased( ) );
}
public static Predicate< ISlip > On( IDock dock ) {
return slip => dock.Equals( slip.Dock( ) );
}
}
}
The base specification class becomes a quick and easy…
public class Specification< T > : ISpecification< T > {
public Specification( Predicate< T > criteriaToSatisfy ) {
_criteriaToSatisfy = criteriaToSatisfy;
}
public bool IsSatisfiedBy( T item ) {
return _criteriaToSatisfy( item );
}
private readonly Predicate< T > _criteriaToSatisfy;
}