Конструктивное решение необходимо для сценария Проверки

Я хотел бы проверить некоторые объекты. Проверка имеет две части:

  • проверка, имеет ли пользователь право получить доступ к объекту (определенные права уже вычисляются и хранятся в булевых значениях, там максимальна 4 роли),
  • проверка, находится ли объект в определенном состоянии (от ряда состояний)

У меня есть много правил (на самом деле, приблизительно 25 всего) как те ниже этого должен быть проверен:

  • isOwner && (состояние == 11 || состояние == 13 || состояние == 14)
  • ! (состояние isOwner && isReceiver && == 12)
  • .....

Я имею, они исключают распространение в нескольких методах, 4 или 5 правилах в методе. Если правило перестало работать затем, другие правила не становятся проверенными. Я должен создать блок проверки допустимости (или настроить уже созданный) в каждом методе, который использует эту проверку.

Я ищу шаблон разработки, который помог бы создать структуру для проверки объектов. Моя цель состоит в том, чтобы смочь предоставить определенные сообщения об ошибках. Например, если проверка перестала работать, потому что пользователь не имеет прав затем, я хочу позволить ему знать это. Если это перестало работать, потому что состояние объекта затем я хочу отобразить это.

Сначала я, хотя из шаблона "декоратор". У меня есть объект-обработчик сообщения об ошибке, который мог быть украшен определенными сообщениями об ошибках. Один декоратор проверил бы на пользовательские права и другой для состояний. Но порядок, в котором я создаю свои объекты блока проверки допустимости, не имеет значения, таким образом, питание шаблона "декоратор" не используется. (AFAIK это - одно большое преимущество использования декоратора - смешивание художественных оформлений). Я думаю, что цепочка могла бы быть лучше для этого случая...?!?! Какую альтернативу дизайна Вы рекомендовали бы для этого сценария?

5
задан Toby Allen 16 July 2010 в 20:47
поделиться

4 ответа

Вместо того, чтобы думать о том, какой шаблон использовать , подумайте о том, какие объекты имеют смысл и каким должно быть их поведение.

В этом случае вы хотите передать объект ряду правил. Если одно из правил не выполняется, это вызывает сообщение, а остальные правила не проверяются (это правильно)?

Если да, то вы заметите, что то, о чем мы не говорим, сценарий, в котором данные передаются всем правилам в цепочке ... что указывает на шаблон цепочки команд, а не на декоратор.

С другой стороны, если вы хотите передать это всем правилам, для меня это больше похоже на шаблон посетителя.

Придумайте идеальное решение, а затем определите закономерность. Не начинайте с попытки найти шаблон, который можно применить.

2
ответ дан 14 December 2019 в 18:54
поделиться

Я бы использовал цепочку ответственности. Вы заставляете ваш объект проходить через цепочку.

1
ответ дан 14 December 2019 в 18:54
поделиться

Вы должны использовать паттерн стратегии для этого сценария, потому что вам нужны разные алгоритмы для заданной роли пользователя (isOwner) и кода статуса.

1
ответ дан 14 December 2019 в 18:54
поделиться

Используйте стратегию (например: список или правила для проверки) + государственную машину (например: перечисление с выходом (.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();
        }
    }
1
ответ дан 14 December 2019 в 18:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: