views:

93

answers:

5

I would like to validate some objects. The validation has two parts:

  • validation whether the user has right to access the object (the specific rights are already calculated and stored in boolean values, there are maximum 4 roles)
  • checking if the object is in a certain state (from a set of states)

I have a lot of rules (actually around 25 in total ) like the ones below that need to be validated:

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

I have these rules spread out in several methods, 4 or 5 rules in a method. If a rule fails then the other rules do not get checked. I need to construct a validator (or set up an already constructed one) in every method that uses this validation.

I am looking for a design pattern that would make it easier to build a structure to validate objects. My goal is to be able to provide specific error messages. For instance if the validation failed because the user doesn't have rights then I want to let him/her know this. If it failed because the object's state then I want to display that .

First I though of the decorator pattern. I have an error message handler object that could be decorated with the specific error messages. One decorator would check for user rights and another one for states. But the order in which I am constructing my validator objects does not matter so the power of decorator pattern is not used. (AFAIK this is one big advantage of using decorator - mixing the decorations). I think a chain might be better for this case...?!?! What design alternative would you recommend for this scenario?

+1  A: 

You should use strategy pattern for this scenario because you need different algorithms for given user role (isOwner) and status code.

šljaker
I don't need algorithms for the status code. The validator for the status code simply checks if the status is one of the statuses allowed. It simply checks if a object's status is in a list. The list is the objects that is changing from validator to validator.
Atticus
Ok, so you can remove status from factory witch will instantiate concrete strategy.
šljaker
So you mean a factory pattern combined with stratergy?
Atticus
Ofcourse. That's what I do when I have too many IFs
šljaker
Plus, when you use combination of factory and strategy pattern it's a way easier to refactor your validation logic then to stuck with IFs.
šljaker
+2  A: 

Instead of thinking about what pattern to use, think about what objects make sense, and what their behaviors should be.

In this case, what you want to do is pass an object to a series of rules. If it fails one of the rules, that will trigger a message, and the rest of the rules don't get checked (is that correct)?

If so, you'll notice that what we're not talking about a scenario where the data is passed to all of the rules in the chain... which is indicative of a chain of command pattern, rather than a decorator.

On the other hand, if you want to pass it to all of the rules, it sounds to me almost more like a visitor pattern.

Think of the ideal solution, and then identify the pattern. Don't start by trying to find a pattern to apply.

kyoryu
If a rules fails then the rest of rules don't get checked. I don't necessarily need a design pattern I wanted to know what could be a best structure for this scenario?
Atticus
@Atticus: If a rule decides to 'handle' the object, it will send a message and stop processing rules. Otherwise, it hands it to the next rule... sounds like a classic Chain of Command.
kyoryu
@kyoryu: Ok, this sounds pretty good for this scenario. I can create my commands or I call them handlers and put them in a chain. I will have one abstract chain class or maybe interface that will have a validate method.My other question is then where should I store the standard roles and statuses to which I am comparing everything in the command or handler classes. Should I put them in the abstract class from which all the commands/handlers are derived? Or should these handler classes get them from somewhere else?
Atticus
Aren't these rules dependent on one another? What handlers would you have in the chain? For example, having UserHandler separate from StateHandler wouldn't work because access is dependent on the state of the object. Or don't I understand?
rioch
I have created only one handler because the state and role rules are dependent on one another hence I have created only one rule that checks for a list of roles and a list of states. I have put the standard roles and states to which I am comparing in the child class. Thanks again for the advices!
Atticus
+1  A: 

I would use a chain of responsability. You make your object to pass through the chain.

onof
+1  A: 

Use strategy (for example: list or rules to be checked) + state machine (for example: enumeration with yield (.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();
        }
    }
igor
A: 

I would likely use the Specification Pattern from DDD, and then use something like the Composite Specification to chain up all the different parts you need.

Check out this thread

Markus Andersson