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;
        }
    }

这是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];
        }
    }

呵呵,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;

                _dict.AddValue(name, ParameterFactory.Create(name, value));
            }
        }

        public Parameter this[string key]
        {
            get { return _dict[key]; }
        }

        public IEnumerator<Parameter> GetEnumerator()
        {
            foreach (var item in _dict)
            {
                yield return item.Value;
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return 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);
            }
        }

代码最会说话,我就不废话了,可以看到这是一个还没完工的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;
        }

    }

方法内部我没写如何实现,无外乎就是反射,所以大家理解思路即可。先判断是否有特殊的name,然后再判断是否有特殊的value,最后再是最普通的。

这样感觉就灵活的很多,而且如果用户想自定义一些function扩展,自需要在这几的程序集的特定名字空间下实现Parameter的继承,系统会自动find到这个特殊name或value。 不过实际应用中貌似这种需求不是很多,一般系统提供的足够用了。

写了好几个小时,才刚写好Parameter,后面再说Field的吧,Field还是比较复杂的。

posted @ 2010-11-11 23:50  君之蘭  阅读(3911)  评论(8编辑  收藏  举报