Creo que mucho de esto dependerá del alcance del proyecto y de lo poco acoplado que sea necesario. Trabajo mucho en torno a las reglas comerciales, y deben ser lo más extensibles posible. No me vincularía a un sistema de reglas ordinales si existe el más mínimo volumen de reglas, o el orden de las mismas es remotamente complejo. Creo que el autodescubrimiento/cableado de las reglas es absolutamente el camino a seguir aquí.
La clave para este tipo de situación, en mi opinión, es que las reglas de casos generales son no definidas por una ausencia de lógica relacionada con su alcance. Las reglas de casos generales deben tener una lógica de alcance tan específica como las reglas de casos específicos. Pueden estar en el alcance 99 de 100 veces, pero aún necesitan tener una lógica de alcance específica.
Lo siguiente es más o menos cómo abordaría esto. No me entusiasma que WithinScope() esté conectado directamente a IRule, pero dado que está considerando una lista ordinal, asumo que la lógica es manejable y relativamente estática, o que podría inyectar un delegado para esa lógica.
Interfaces marco
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();
}
Genérico Validador y la Regla de fábrica
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());
}
}
reglas de ejemplo
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;
}
}
COI cableado (Usando 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<>));
});
}
}
muy molesto problema. Lo he debatido durante horas y no he llegado a una solución satisfactoria. – CodesInChaos
Considere renunciar al autodescubrimiento y cree manualmente una lista central de reglas en orden de prioridad. – CodesInChaos
Mire el concepto de regla web (http://rule.codeeffects.com). Creo que estás buscando algo similar a lo que hacen. – Kizz