之前由於工作的原因,寫過一個通用網站數據采集的小工具,通過配置XML來采集不同的網站內容。
這段時間工作閑暇之余,覺得有必要重構一下,順便學習學習,特此記錄。
字符處理規則重構
字符處理應該算是采集中得一個核心內容,如果在一大串HTML字符串中提取成我們需要的字段。先看看之前的處理方式:

string temp2; temp2 = GetStr(str, MyConfig.Url, Lev); //字符截取規則 temp2 = ReplaceStr(temp2, MyConfig.UrlGL, Lev); //字符過濾規則 temp2 = SetCodeing(temp2, MyConfig.UrlBM, Lev);//字符URL編碼規則 temp2 = Myreplace(temp2,MyConfig.UrlGvContent,Lev);//字符替換規則
分析毛病:
1. 客戶端調用次數太多,如果有四個規則則需要調用四個規則。
2. 擴展不靈活,如果以后遇到新的采集需求而現有的規則不滿足要求,需要添加新的規則,則不符合“開閉原則”
下面讓我們開始重構吧:
1. 提取公用的規則接口

/// <summary> /// 文字處理規則接口 /// </summary> public interface ItextRule { /// <summary> /// 字符處理 /// </summary> /// <param name="sourceStr">待處理字符串</param> /// <param name="key">配置關鍵字</param> /// <param name="lev">當前層級</param> /// <returns></returns> string TextPro(string sourceStr,string key,int lev); }
2. 建立規則類的抽象類,寫入一些公用的方法

/// <summary> /// 字符處理規則基礎類 /// </summary> public abstract class TextRuleBase { private string myKey = string.Empty; public TextRuleBase(string _key) { myKey = _key; } /// <summary> /// 獲取配置文件的值 /// </summary> /// <param name="key"></param> /// <param name="lev"></param> /// <returns></returns> protected string[] GetValue(string key,int lev) { string str = string.Empty; string temp = string.Empty; string tempKey = key + myKey + lev; bool Istrue = true; while(Istrue) //循環讀配置,知道為空 { temp = SiteConfig.ConfigByKey(tempKey); if (temp == "") { Istrue = false; } else { str += temp + "|"; tempKey += lev; } } return str.Split(new char[]{'|'},StringSplitOptions.RemoveEmptyEntries); } /// <summary> /// 具體規則處理 強制子類實現 /// </summary> /// <param name="sourceStr"></param> /// <param name="Content"></param> /// <returns></returns> protected abstract string TextPro(string sourceStr, string[] Contents); }
3. 建立字符規則類,按照上面的邏輯分別建立4個字符規則類,繼承接口和抽象類

/// <summary> /// 字符截取規則 基本規則 /// </summary> public class TextIntercept :TextRuleBase, ItextRule { public TextIntercept():base("") { } #region ItextRule 公開成員 /// <summary> /// 字符截取規則具體實現(多次) /// </summary> /// <param name="sourceStr"></param> /// <param name="key"></param> /// <param name="lev"></param> /// <returns></returns> public string TextPro(string sourceStr, string key, int lev) { return TextPro(sourceStr,GetValue(key,lev)); } #endregion #region 內部強制私有方法 /// <summary> /// 字符截取規則具體實現(多次) /// </summary> /// <param name="sourceStr"></param> /// <param name="Content"></param> /// <returns></returns> protected override string TextPro(string sourceStr, string[] Contents) { string relText = sourceStr; foreach (string value in Contents) { if (value != "") { relText = Function.GetStr(relText, value, MyConfig.Key); } } Console.WriteLine("字符截取規則結果:" + relText); Console.WriteLine(""); return relText; } #endregion }
這里就只建立一個示例,其他同。或詳見CODE
4. 建立一個高層接口,供客戶端直接調用,內部封裝好各種規則(根據配置)

/// <summary> /// 字符處理規則的高層接口 /// </summary> public class TextRuleAll:ItextRule { private Dictionary<string, IList<ItextRule>> ruleList = new Dictionary<string, IList<ItextRule>>(); #region ItextRule 成員 public string TextPro(string sourceStr, string key, int lev) { string dicKey = key + lev; string returnStr = string.Empty; if (!ruleList.ContainsKey(dicKey)) { IList<ItextRule> list = new List<ItextRule>(); #region 根據配置構建關鍵字規則列表 foreach (string vale in MyConfig.AllTextRules()) { string[] temp = vale.Split('.'); string xmlKey = temp[temp.Length - 1]; if (xmlKey == "TextIntercept") //寫死 字符截取規則為基本規則 xmlKey = ""; if (SiteConfig.ConfigByKey(key + xmlKey + lev) != "") //XML文件有此配置關鍵字 { list.Add((ItextRule)Assembly.Load("Demo1").CreateInstance(vale)); } } #endregion ruleList.Add(dicKey,list); } IList<ItextRule> mylist = ruleList[dicKey]; if (mylist != null && mylist.Count > 0) //循環執行各種規則處理 { returnStr = sourceStr; foreach (ItextRule irule in mylist) returnStr = irule.TextPro(returnStr, key, lev); } return returnStr; } #end
5. 配置文件

<MyConfig> <!--字符處理擴展規則列表--> <!--TextIntercept為截取規則--> <!--StaticReplace為靜態替換規則--> <AllTextRules>Collect.TextRule.TextIntercept,Collect.TextRule.StaticReplace,Collect.TextRule.TextUrlEncode,Collect.TextRule.TextFilter</AllTextRules> <!--TextIntercept截取規則配置--> <Name1>郵件地址是[內容]</Name1> <!--StaticReplacej靜態替換配置--> <NameStaticReplace1>#,@</NameStaticReplace1> <NameStaticReplace11>fuwentao,fwt</NameStaticReplace11> <!--中文URL編碼規則配置--> <NameTextUrlEncode1>city=[內容]</NameTextUrlEncode1> <!--過濾規則配置--> <NameTextFilter1>.com,[內容]http</NameTextFilter1> </MyConfig>
重構完了,讓我們再看看客戶端的調用:
string testStr = "我是fuwentao,我的郵件地址是fwt1314111#163.com,網址http://www.mywaysoft.net/city=上海"; TextRuleAll cmd = new TextRuleAll(); string rel= cmd.TextPro(testStr, "Name", 1); //結果
就一句cmd.TextPro搞定!是不是比之前簡單多了。
並且,這樣靈活性也很強,以后如果要增加新的處理規則,則只需要建立一個規則類,然后再配置文件中配置一下就OK啦。