我认为这在很大程度上取决于项目的范围以及你需要多么松散地耦合。我做了很多与业务规则相关的工作,它们需要尽可能具有可扩展性。如果规则数量稍微有点大,或者它们的排序甚至稍微复杂一些,我不会将自己绑定在序数规则系统上。我认为自动发现/连接规则绝对是此处的最佳选择。
在我看来,这种情况的关键是,一般情况下的规则并不是由与其范围相关的逻辑缺失所定义的。一般情况下的规则必须具有与特定情况下的规则一样具体的范围逻辑。它们可能在100次中有99次在范围内,但它们仍然需要具有具体的范围逻辑。
以下大致是我的处理方法。我不太喜欢将WithinScope()直接附加到IRule,但考虑到您正在考虑一个序数列表,我假设该逻辑要么是可管理且相对静态的,要么可以注入一个委托来处理该逻辑。
框架接口
public interface IRule<in T>{
bool IsValid(T obj);
bool WithinScope();
}
public interface IValidator<in T>{
bool IsValid(T obj);
}
public interface IRuleFactory<in T>{
IEnumerable<IRule<T>> BuildRules();
}
通用验证器和规则工厂
public class GenericValidator<T> : IValidator<T>
{
private readonly IEnumerable<IRule<T>> _rules;
public GenericValidator(IRuleFactory<T> ruleFactory){
_rules = ruleFactory.BuildRules();
}
public bool IsValid(T obj){
return _rules.All(p => p.IsValid(obj));
}
}
public class GenericRuleFactory<T> : IRuleFactory<T>
{
private readonly IEnumerable<IRule<T>> _rules;
public GenericRuleFactory(IEnumerable<IRule<T>> rules){
_rules = rules;
}
public IEnumerable<IRule<T>> BuildRules(){
return _rules.Where(x => x.WithinScope());
}
}
示例规则
public class VeryGeneralDefaultRuleAboutAllObjects : IRule<IMyClass>
{
private readonly Context _context;
public VeryGeneralDefaultRuleAboutAllObjects(Context context){
_context = context;
}
public bool IsValid(IMyClass obj){
return !obj.IsAllJackedUp;
}
public bool WithinScope(){
return !_context.IsSpecialCase;
}
}
public class SpecificCaseWhenGeneralRuleDoesNotApply : IRule<IMyClass>
{
private readonly Context _context;
public VeryGeneralDefaultRuleAboutAllObjects(Context context){
_context = context;
}
public bool IsValid(IMyClass obj){
return !obj.IsAllJackedUp && _context.HasMoreCowbell;
}
public bool WithinScope(){
return _context.IsSpecialCase;
}
}
IoC装配(使用StructureMap)
public static class StructureMapBootstrapper
{
public static void Initialize()
{
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.AssembliesFromApplicationBaseDirectory();
scan.AddAllTypesOf(typeof (IRule<>));
});
x.For(typeof(IValidator<>))
.Use(typeof(GenericValidator<>));
x.For(typeof(IRuleFactory<>))
.Use(typeof(GenericRuleFactory<>));
});
}
}