[转载]CMS系统模板引擎设计(4):Parameter类设计 – 氣如蘭兮長不改,心若蘭兮終不移。 – 博客园.
紧接上回,说到Parameter和Field了。
在 Label初始化的时候,同时也要对ParameterCollection和FiledCollection初始化。在上节有个属性是这样写的 ArticleId=Url(articleid),意思是ArticleId 的值是url的query里的articleid的参数的值。而且还有个 DateFormat=”yyyy年MM月dd日”。所以可以看出Parameter的多样化,我个人认为Parameter是最难设计的!以至于我现在 写博文都心虚,我之前的系统里对Parameter处理的也比较糟糕,有不少hardcode。
我们说下Parameter的麻烦之处:
1、我们具体Label(Article的List)需要获取Parameter的值,有int string bool等,所以Parameter需要把本身的value可转成任意基础类型
2、有的Parameter的value不是具体值,而是一个方法调用,我们需要反射这个方法,这个方法存在哪里?Core还是具体的某个模块(比如文章)实现的
3、像Format之类的Parameter显然是用来处理“后事”的,他不会用到前期取值,而是得到后的format工作,也就是需要传一个未知的值。
4、如何做到Label也可以用,Field也可以用。前者主要用做参数,后者主要用来format。当然,前者有时也format。
带着这几个问题,我们想想Parameter应该有什么样的内容?
/// <summary>
/// Label参数类
/// </summary>
public class Parameter
{
/// <summary>
/// 参数名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 参数初始值
/// </summary>
public string Value { get; set; } public Parameter() { }
public Parameter(string name, string value)
{
Name = name;
Value = value;
}
/// <summary>
/// 获取参数最终值(默认为初始值)
/// </summary>
/// <param name=”parameters”></param>
/// <returns></returns>
public virtual string GetValue(params string[] parameters)
{
return Value;
}
}
/// Label参数类
/// </summary>
public class Parameter
{
/// <summary>
/// 参数名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 参数初始值
/// </summary>
public string Value { get; set; } public Parameter() { }
public Parameter(string name, string value)
{
Name = name;
Value = value;
}
/// <summary>
/// 获取参数最终值(默认为初始值)
/// </summary>
/// <param name=”parameters”></param>
/// <returns></returns>
public virtual string GetValue(params string[] parameters)
{
return Value;
}
}
这是Parameter基类,那么Url等特殊的参数我设计成了子类!
public class Url : Parameter
{
public override string GetValue(params string[] parameters)
{
return PageCollection.GetCurrentPage().UrlPattern.GetValue(RequestUtility.Rawurl(), Name);
}
} public class Format : Parameter
{
public override string GetValue(params string[] parameters)
{
if (parameters == null) return string.Empty;
var val = parameters[0];
return Value.Replace(“@me“, val);
}
} public class DateFormat : Parameter
{
public override string GetValue(params string[] parameters)
{
if (parameters == null) return string.Empty;
DateTime t;
if (DateTime.TryParse(parameters[0], out t))
{
return t.ToString(Value);
}
return parameters[0];
}
}
{
public override string GetValue(params string[] parameters)
{
return PageCollection.GetCurrentPage().UrlPattern.GetValue(RequestUtility.Rawurl(), Name);
}
} public class Format : Parameter
{
public override string GetValue(params string[] parameters)
{
if (parameters == null) return string.Empty;
var val = parameters[0];
return Value.Replace(“@me“, val);
}
} public class DateFormat : Parameter
{
public override string GetValue(params string[] parameters)
{
if (parameters == null) return string.Empty;
DateTime t;
if (DateTime.TryParse(parameters[0], out t))
{
return t.ToString(Value);
}
return parameters[0];
}
}
呵呵,GetValue貌似不是很漂亮,但确实解决了传值不定的情况。那我们如何实例化ParameterCollection的呢?(其实就是看怎么实例化这些Parameter的)
/// <summary>
/// Parameter集合
/// </summary>
public class ParameterCollection : IEnumerable<Parameter>
{
private static readonly Regex FindPattern = new Regex(@”(?<name>\w+)=(?<value>(“”([^””]+)””)|(‘[^’]+’)|([^\s\}]+))“, RegexOptions.Compiled); private readonly IDictionary<string, Parameter> _dict; public ParameterCollection(string parameterString)
{
//两个return都会造成_dict为null,枚举此类的时候会抛异常,所以把dict实现实例化了
_dict = new Dictionary<string, Parameter>(); if (parameterString == string.Empty) return;
var matches = FindPattern.Matches(parameterString);
if (matches.Count == 0) return; //开始初始化所有Parameter
foreach (Match m in matches)
{
var name = m.Groups[“name“].Value;
var value = m.Groups[“value“].Value;
{
get { return _dict[key]; }
} public IEnumerator<Parameter> GetEnumerator()
{
foreach (var item in _dict)
{
yield return item.Value;
}
}
}
}
/// Parameter集合
/// </summary>
public class ParameterCollection : IEnumerable<Parameter>
{
private static readonly Regex FindPattern = new Regex(@”(?<name>\w+)=(?<value>(“”([^””]+)””)|(‘[^’]+’)|([^\s\}]+))“, RegexOptions.Compiled); private readonly IDictionary<string, Parameter> _dict; public ParameterCollection(string parameterString)
{
//两个return都会造成_dict为null,枚举此类的时候会抛异常,所以把dict实现实例化了
_dict = new Dictionary<string, Parameter>(); if (parameterString == string.Empty) return;
var matches = FindPattern.Matches(parameterString);
if (matches.Count == 0) return; //开始初始化所有Parameter
foreach (Match m in matches)
{
var name = m.Groups[“name“].Value;
var value = m.Groups[“value“].Value;
_dict.AddValue(name, ParameterFactory.Create(name, value));
}
}
{
get { return _dict[key]; }
} public IEnumerator<Parameter> GetEnumerator()
{
foreach (var item in _dict)
{
yield return item.Value;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
}
}
其中的AddValue是我写的扩展方法:
代码
public static void AddValue<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue value)
{
if (dict.ContainsKey(key))
{
dict[key] = value;
}
else
{
dict.Add(key, value);
}
}
{
if (dict.ContainsKey(key))
{
dict[key] = value;
}
else
{
dict.Add(key, value);
}
}
代码最会说话,我就不废话了,可以看到这是一个还没完工的Collection,而创建Parameter部分不在这,在Factory 哈哈。
public static class ParameterFactory
{
private static readonly Regex FuncPattern = new Regex(@”(?<func>\w+)\((?<parameter>[^)(]+?)\)“, RegexOptions.Compiled);
/// <summary>
/// 获取一个Parameter
/// </summary>
/// <param name=”name”></param>
/// <param name=”value”></param>
/// <returns></returns>
public static Parameter Create(string name, string value)
{
Parameter parameter;
if (IsSpecialParameter(name))
{
parameter = GetParameterByName(name);
}
else if (FuncPattern.IsMatch(value))
{
parameter = GetParameterByName(name);
}
else
{
parameter = new Parameter(name, value);
}
return parameter;
}
/// <summary>
/// 是否为特殊名称的Parameter
/// </summary>
/// <param name=”name”></param>
/// <returns></returns>
private static bool IsSpecialParameter(string name)
{
return false;
}
/// <summary>
/// 根据参数名获取Parameter(例如format=”e.g@me”)
/// </summary>
/// <param name=”name”></param>
/// <returns></returns>
private static Parameter GetParameterByName(string name)
{
//通过反射创建Parameter类
return null;
}
/// <summary>
/// 根据参数值获取Parameter(例如”Url(articleid)”)
/// </summary>
/// <param name=”value”></param>
/// <returns></returns>
private static Parameter GetParameterByValue(string value)
{
return null;
}
{
private static readonly Regex FuncPattern = new Regex(@”(?<func>\w+)\((?<parameter>[^)(]+?)\)“, RegexOptions.Compiled);
/// <summary>
/// 获取一个Parameter
/// </summary>
/// <param name=”name”></param>
/// <param name=”value”></param>
/// <returns></returns>
public static Parameter Create(string name, string value)
{
Parameter parameter;
if (IsSpecialParameter(name))
{
parameter = GetParameterByName(name);
}
else if (FuncPattern.IsMatch(value))
{
parameter = GetParameterByName(name);
}
else
{
parameter = new Parameter(name, value);
}
return parameter;
}
/// <summary>
/// 是否为特殊名称的Parameter
/// </summary>
/// <param name=”name”></param>
/// <returns></returns>
private static bool IsSpecialParameter(string name)
{
return false;
}
/// <summary>
/// 根据参数名获取Parameter(例如format=”e.g@me”)
/// </summary>
/// <param name=”name”></param>
/// <returns></returns>
private static Parameter GetParameterByName(string name)
{
//通过反射创建Parameter类
return null;
}
/// <summary>
/// 根据参数值获取Parameter(例如”Url(articleid)”)
/// </summary>
/// <param name=”value”></param>
/// <returns></returns>
private static Parameter GetParameterByValue(string value)
{
return null;
}
}
方法内部我没写如何实现,无外乎就是反射,所以大家理解思路即可。先判断是否有特殊的name,然后再判断是否有特殊的value,最后再是最普通的。
这样感觉就灵活的很多,而且如果用户想自定义一些function扩展,自需要在这几的程序集的特定名字空间下实现Parameter的继承,系统会自动find到这个特殊name或value。 不过实际应用中貌似这种需求不是很多,一般系统提供的足够用了。
写了好几个小时,才刚写好Parameter,后面再说Field的吧,Field还是比较复杂的。