目前想到的可以使用规约模式的情况(以后想到了再补充):
1. 当有一组条件,被多处使用,且这些条件可以任意组合时,这个时候考虑使用规约模式来解耦;
下面看一下规约模式的简单实现:
public interface ISpecification<T> where T : class { bool IsSatisfiedBy( T item ); } public abstract class Specification<T> : ISpecification<T> where T : class { #region ISpecification<T> 成员 public abstract bool IsSatisfiedBy( T item ); #endregion public ISpecification<T> And( ISpecification<T> other ) { return new AndSpecification<T>( this, other ); } public ISpecification<T> Or( ISpecification<T> other ) { return new OrSpecification<T>( this, other ); } public ISpecification<T> Not() { return new NotSpecification<T>( this ); } } public class AndSpecification<T> : Specification<T> where T : class { private readonly ISpecification<T> _left; private readonly ISpecification<T> _right; public AndSpecification( ISpecification<T> left, ISpecification<T> right ) { if ( left == null ) throw new ArgumentNullException( "left" ); if ( right == null ) throw new ArgumentNullException( "right" ); this._left = left; this._right = right; } public override bool IsSatisfiedBy( T item ) { return this._left.IsSatisfiedBy( item ) && this._right.IsSatisfiedBy( item ); } } public class OrSpecification<T> : Specification<T> where T : class { private readonly ISpecification<T> _left; private readonly ISpecification<T> _right; public OrSpecification( ISpecification<T> left, ISpecification<T> right ) { if ( left == null ) throw new ArgumentNullException( "left" ); if ( right == null ) throw new ArgumentNullException( "right" ); this._left = left; this._right = right; } public override bool IsSatisfiedBy( T item ) { return this._left.IsSatisfiedBy( item ) || this._right.IsSatisfiedBy( item ); } } public class NotSpecification<T> : Specification<T> where T : class { private readonly ISpecification<T> _left; public NotSpecification( ISpecification<T> left ) { if ( left == null ) throw new ArgumentNullException( "left" ); this._left = left; } public override bool IsSatisfiedBy( T item ) { return !this._left.IsSatisfiedBy( item ); } } public class NameSpecification : Specification<UserInfo> { public override bool IsSatisfiedBy( UserInfo item ) { if ( item == null ) throw new ArgumentNullException( "item" ); return item.Name.StartsWith( "JR", StringComparison.InvariantCultureIgnoreCase ); } } public class AgeSpecification : Specification<UserInfo> { public override bool IsSatisfiedBy( UserInfo item ) { if ( item == null ) throw new ArgumentNullException( "item" ); return item.Age > 15; } } public class UserInfo { public string Name { get; set; } public int Age { get; set; } }
其中 UserInfo 是一个测试类,NameSpecification, AgeSpeicification 是两个规约模式的实现。下面看一下测试代码:
public class SpecificationTest { public void RunTest() { var users = new List<UserInfo> { new UserInfo{ Name = "JRoger1", Age = 11}, new UserInfo{ Name = "roger1", Age = 12}, new UserInfo{ Name = "JRoger2", Age = 18}, }; var nameSpec = new NameSpecification(); var ageSpec = new AgeSpecification(); var andSpec = nameSpec.And( ageSpec ); var orSpec = nameSpec.Or( ageSpec ); var notSpec = nameSpec.Not(); Console.WriteLine( "Name Specification ... " ); foreach ( var item in users ) { if ( nameSpec.IsSatisfiedBy( item ) ) { Console.WriteLine( item.Name ); } } Console.WriteLine(); Console.WriteLine( "Age Specification ... " ); foreach ( var item in users ) { if ( ageSpec.IsSatisfiedBy( item ) ) { Console.WriteLine( item.Name ); } } Console.WriteLine(); Console.WriteLine( "And Specification ... " ); foreach ( var item in users ) { if ( andSpec.IsSatisfiedBy( item ) ) { Console.WriteLine( item.Name ); } } Console.WriteLine(); Console.WriteLine( "Or Specification ... " ); foreach ( var item in users ) { if ( orSpec.IsSatisfiedBy( item ) ) { Console.WriteLine( item.Name ); } } Console.WriteLine(); Console.WriteLine( "Not Specification ... " ); foreach ( var item in users ) { if ( notSpec.IsSatisfiedBy( item ) ) { Console.WriteLine( item.Name ); } } Console.ReadLine(); } }
关于规约模式,网上也有很多讲解的。关键还是理解其是在什么情景下提出来的方法。至于规约模式的实现,基本思想是一样的。但是各种语言有根据各种语言的特性实现的版本,C#版的有一个比较好的使用 Lambda 表达式实现的。上面的实现版本算是中规中矩的。