2010-07-16 12 views
5

Me gustaría validar algunos objetos. La validación tiene dos partes:Solución de diseño necesaria para el escenario de validación

  • validación si el usuario tiene derecho a acceder al objeto (los derechos específicos ya se calculan y almacenan en valores booleanos, hay un máximo de 4 papeles)
  • comprobar si el objeto está en un cierto estado (de un conjunto de estados)

que tiene un montón de reglas (en realidad alrededor de 25 en total) como los siguientes que deben ser validados:

  • isOwner & & (estado == 11 || estado == 13 || == estado 14)
  • ! (IsOwner & & isReceiver & & estado == 12)
  • .....

He estas reglas se extendió a cabo en varios métodos, 4 o 5 en reglas un método. Si una regla falla, las demás reglas no se verifican. Necesito construir un validador (o configurar uno ya construido) en cada método que use esta validación.

Estoy buscando un patrón de diseño que facilite la construcción de una estructura para validar objetos. Mi objetivo es poder proporcionar mensajes de error específicos. Por ejemplo, si la validación falla porque el usuario no tiene derechos, entonces quiero que lo sepa. Si falló debido al estado del objeto, entonces quiero mostrar ese .

Primero pensé en el patrón del decorador. Tengo un objeto controlador de mensajes de error que podría decorarse con los mensajes de error específicos. Un decorador verificaría los derechos de los usuarios y otro para los estados. Pero el orden en el que estoy construyendo mis objetos validador no importa, por lo que no se usa el poder del patrón decorador. (AFAIK esta es una gran ventaja de usar decorador - mezcla de decoraciones). Creo que una cadena podría ser mejor para este caso ...?!?! ¿Qué alternativa de diseño recomendaría para este escenario?

+0

¿Está utilizando .net yC#? – garik

+0

@igor: ¿debería importar? – cherouvim

+0

@igor: Creo que no importa, la idea es aplicable en todos los idiomas. Por cierto, estoy usando Java. – Atticus

Respuesta

2

En lugar de pensar qué patrón usar, piense en qué objetos tienen sentido y cuáles deberían ser sus comportamientos.

En este caso, lo que quiere hacer es pasar un objeto a una serie de reglas. Si falla una de las reglas, desencadenará un mensaje, y el resto de las reglas no se verifican (¿es correcto)?

Si es así, notará que no estamos hablando de un escenario donde los datos se pasan a todas las reglas de la cadena ... que es indicativo de un patrón de cadena de comandos, en lugar de un decorador.

Por otro lado, si desea pasarlo a todas las reglas, me suena casi como un patrón de visitante.

Piense en la solución ideal y luego identifique el patrón. No empiece tratando de encontrar un patrón para aplicar.

+0

Si falla una regla, el resto de las reglas no se verifican. No necesito necesariamente un patrón de diseño. ¿Quería saber cuál podría ser la mejor estructura para este escenario? – Atticus

+1

@Atticus: si una regla decide 'manejar' el objeto, enviará un mensaje y detendrá las reglas de procesamiento. De lo contrario, se lo pasa a la siguiente regla ... suena como una cadena de mando clásica. – kyoryu

+0

Ok, esto suena bastante bien para este escenario. Puedo crear mis comandos o los llamo manejadores y los pongo en una cadena. Tendré una clase de cadena abstracta o tal vez una interfaz que tendrá un método de validación. Mi otra pregunta es entonces, ¿dónde debo guardar las funciones y estados de tipo a las que estoy comparando todo en las clases de mando o manipulador. ¿Debería ponerlos en la clase abstracta de la cual se derivan todos los comandos/manejadores? ¿O deberían estas clases de controladores obtenerlas de otro lugar? – Atticus

1

Debe utilizar el patrón de estrategia para este escenario porque necesita diferentes algoritmos para la función de usuario determinada (isOwner) y el código de estado.

+0

No necesito algoritmos para el código de estado. El validador del código de estado simplemente verifica si el estado es uno de los permitidos. Simplemente verifica si el estado de un objeto está en una lista. La lista es los objetos que están cambiando de validador a validador. – Atticus

+0

Ok, para que pueda eliminar el estado de fábrica que creará una estrategia concreta. –

+0

¿Te refieres a un patrón de fábrica combinado con estratagema? – Atticus

1

me gustaría utilizar una cadena de responsabilidad. Haces que tu objeto pase a través de la cadena.

1

Uso estrategia (por ejemplo: lista o reglas para ser comprobados) + máquina de estado (por ejemplo: enumeración con el rendimiento (NET)).

class Program 
    { 
     public class StateObject 
     { 
      public virtual int State { get; set; } 
     } 

     public abstract class Rule 
     { 
      public abstract Result Check(StateObject objectToBeChecked); 

     } 

     public class DefaultAllow : Rule 
     { 
      public override Result Check(StateObject objectToBeChecked) 
      { 
       Console.WriteLine("DefaultAllow: allow"); 
       return Result.Allow; 
      } 
     } 

     public class DefaultDeny : Rule 
     { 
      public override Result Check(StateObject objectToBeChecked) 
      { 
       Console.WriteLine("DefaultDeny: deny"); 
       return Result.Deny; 
      } 
     } 

     public class DefaultState : Rule 
     { 
      public override Result Check(StateObject objectToBeChecked) 
      { 
       Console.WriteLine("DefaultState: state: {0}", objectToBeChecked.State); 
       return objectToBeChecked.State == 1 ? Result.Allow : Result.Deny; 
      } 
     } 

     public class Strategy 
     { 

      public virtual IEnumerable<Rule> GetRules() 
      { 
       return new List<Rule>() 
          { 
           new DefaultAllow(), 
           new DefaultState() 
          }; 
      } 
     } 

     public class Validator 
     { 
      private readonly Strategy _strategy; 

      public Validator(Strategy strategy) 
      { 
       _strategy = strategy; 
      } 

      public IEnumerable<Result> Process(StateObject objectToBeChecked) 
      { 
       foreach (Rule rule in _strategy.GetRules()) 
        yield return rule.Check(objectToBeChecked); 
      } 

     } 

     public class MyStateMachine 
     { 
      private readonly Validator _validator; 
      private StateObject _stateObject; 

      public event EventHandler OnAllow; 
      public event EventHandler OnDeny; 
      public event EventHandler OnError; 

      public MyStateMachine(Validator validator) 
      { 
       _validator = validator; 
      } 

      public void Init(StateObject stateObject) 
      { 
       _stateObject = stateObject; 
      } 

      protected virtual void Validate() 
      { 
       Result result = Result.Allow; // default 

       foreach (Result r in _validator.Process(_stateObject)) 
       { 
        result = r; 
        if (r != Result.Allow) 
         break; 
       } 

       if (result == Result.Allow) 
        Notify(OnAllow); 
       else if (result == Result.Deny) 
        Notify(OnDeny); 
       else if (result == Result.Error) 
        Notify(OnError); 
       else 
        throw new NotSupportedException(); 

       Console.WriteLine("Result: {0}", result); 
      } 


      private void Notify(EventHandler handler) 
      { 
       if (handler != null) 
        handler.Invoke(_stateObject, EventArgs.Empty); 
      } 


      public void ChangeState(int prevState, int newState) 
      { 
       if (prevState != _stateObject.State) 
        throw new InvalidStateException(); 

       _stateObject.State = newState; 

       Validate(); // maybe this, maybe before assign a new state 
      } 
     } 

     public class InvalidStateException : Exception { } 

     public enum Result { Allow, Deny, Error } 


     static void Main(string[] args) 
     { 
      Strategy defaultStrategy = new Strategy(); 
      Validator ruleChecker = new Validator(defaultStrategy); 
      MyStateMachine stateMachine = new MyStateMachine(ruleChecker); 

      StateObject objectToBeChecked = new StateObject(); 
      stateMachine.Init(objectToBeChecked); 

      stateMachine.ChangeState(objectToBeChecked.State, 1); 
      stateMachine.ChangeState(objectToBeChecked.State, 2); 


      Console.ReadLine(); 
     } 
    } 
0

que sería probable que utilice el modelo de especificación de DDD y, a continuación, utilizar algo así como la especificación de material compuesto para encadenar las diferentes piezas que necesita.

Check out this thread

Cuestiones relacionadas