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還是比較複雜的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章