Я хотел бы проверить некоторые объекты. Проверка имеет две части:
У меня есть много правил (на самом деле, приблизительно 25 всего) как те ниже этого должен быть проверен:
Я имею, они исключают распространение в нескольких методах, 4 или 5 правилах в методе. Если правило перестало работать затем, другие правила не становятся проверенными. Я должен создать блок проверки допустимости (или настроить уже созданный) в каждом методе, который использует эту проверку.
Я ищу шаблон разработки, который помог бы создать структуру для проверки объектов. Моя цель состоит в том, чтобы смочь предоставить определенные сообщения об ошибках. Например, если проверка перестала работать, потому что пользователь не имеет прав затем, я хочу позволить ему знать это. Если это перестало работать, потому что состояние объекта затем я хочу отобразить это.
Сначала я, хотя из шаблона "декоратор". У меня есть объект-обработчик сообщения об ошибке, который мог быть украшен определенными сообщениями об ошибках. Один декоратор проверил бы на пользовательские права и другой для состояний. Но порядок, в котором я создаю свои объекты блока проверки допустимости, не имеет значения, таким образом, питание шаблона "декоратор" не используется. (AFAIK это - одно большое преимущество использования декоратора - смешивание художественных оформлений). Я думаю, что цепочка могла бы быть лучше для этого случая...?!?! Какую альтернативу дизайна Вы рекомендовали бы для этого сценария?
Вместо того, чтобы думать о том, какой шаблон использовать , подумайте о том, какие объекты имеют смысл и каким должно быть их поведение.
В этом случае вы хотите передать объект ряду правил. Если одно из правил не выполняется, это вызывает сообщение, а остальные правила не проверяются (это правильно)?
Если да, то вы заметите, что то, о чем мы не говорим, сценарий, в котором данные передаются всем правилам в цепочке ... что указывает на шаблон цепочки команд, а не на декоратор.
С другой стороны, если вы хотите передать это всем правилам, для меня это больше похоже на шаблон посетителя.
Придумайте идеальное решение, а затем определите закономерность. Не начинайте с попытки найти шаблон, который можно применить.
Я бы использовал цепочку ответственности. Вы заставляете ваш объект проходить через цепочку.
Вы должны использовать паттерн стратегии для этого сценария, потому что вам нужны разные алгоритмы для заданной роли пользователя (isOwner) и кода статуса.
Используйте стратегию (например: список или правила для проверки) + государственную машину (например: перечисление с выходом (.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();
}
}