我想验证一些对象。验证有两部分:
我有很多规则(实际上总共大约25个),比如下面那些需要验证的规则:
我将这些规则分散在几种方法中,方法中有4或5个规则。 如果规则失败,则不会检查其他规则。 我需要在每个使用此验证的方法中构造一个验证器(或设置一个已构造的验证器)。
我正在寻找一种设计模式,可以更容易地构建一个结构来验证对象。我的目标是能够提供特定的错误消息。例如,如果验证失败,因为用户没有权限,那么我想让他/她知道这一点。如果由于对象的状态而失败,那么我想显示它
首先我是装饰模式。我有一个错误消息处理程序对象,可以使用特定的错误消息进行修饰。一个装饰器将检查用户权限,另一个装饰器用于状态。但是我构建验证器对象的顺序无关紧要,因此不使用装饰器模式的功能。 (AFAIK这是使用装饰器的一大优势 - 混合装饰)。我认为链条可能更适合这种情况......?!?!您会为此方案推荐哪种设计方案?
答案 0 :(得分:2)
不要考虑使用什么样的模式,而是考虑哪些对象有意义,以及他们的行为应该是什么。
在这种情况下,您要做的是将对象传递给一系列规则。如果它失败了其中一个规则,那将触发一条消息,其余规则不会被检查(这是正确的)吗?
如果是这样,你会注意到我们没有谈论数据传递给链中所有规则的场景......这表明了一系列命令模式,而不是装饰器
另一方面,如果你想将它传递给所有规则,对我来说听起来更像是一个访客模式。
考虑理想的解决方案,然后确定模式。不要试图找到要应用的模式。
答案 1 :(得分:1)
您应该为此方案使用策略模式,因为您需要针对给定用户角色(isOwner)和状态代码使用不同的算法。
答案 2 :(得分:1)
我会使用一系列责任。你让你的对象通过链。
答案 3 :(得分:1)
使用策略(例如:要检查的列表或规则)+状态机(例如:带有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();
}
}
答案 4 :(得分:0)
我可能会使用DDD中的规范模式,然后使用像复合规范之类的东西来链接你需要的所有不同部分。