成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

對設計及重構的一點反思

開發 架構
本項目是一個電子商務類的網站,其中有個功能是在訂單狀態改變到某種狀態后向客戶發送通知短信的功能,短信及網關功能均已封裝為組建的方式,我們直接調用即可。

本文是我對一個項目中一個小功能點的演進及重構過程的一點反思與心得。

背景:

本項目是一個電子商務類的網站,其中有個功能是在訂單狀態改變到某種狀態后向客戶發送通知短信的功能,短信及網關功能均已封裝為組建的方式,我們直接調用即可。

為更清晰明白地說明與本主題相關的功能,在此我以一個控制臺的程序方式說明代碼的演進過程。

重構的演進過程:

最初我們是如大多數項目一樣,為在規定的時間內完成相關功能點而努力奮斗著,這個功能點的主要代碼如下:

  1. v1   
  2.  
  3.         static void SendSMS_V1(DataTable dt)  
  4.         {  
  5.             if (null == dt) return;  
  6.  
  7.             for (int i = 0; i < dt.Rows.Count; i++)  
  8.             {  
  9.                 var row = dt.Rows[i];  
  10.                 OrderStateEnum state = (OrderStateEnum)((int)row["OrderState"]);  
  11.                 string template = string.Empty;  
  12.                 switch (state)  
  13.                 {  
  14.                     case OrderStateEnum.UnConfirmed:  
  15.                         template = "尊敬的{0},你好!你的訂單已成功下達,請盡快付款以便配送。";  
  16.                         break;  
  17.                     case OrderStateEnum.Confirmed:  
  18.                         template = "尊敬的{0},你好!你的訂單(訂單號:{1})已被確認,請耐心等待。";  
  19.                         break;  
  20.                     case OrderStateEnum.Cancel:  
  21.                         template = "尊敬的{0},你好!你的訂單(訂單號:{1})已被取消,具體原因請上網查看。";  
  22.                         break;  
  23.                     case OrderStateEnum.Finish:  
  24.                         template = "尊敬的{0},你好!你的訂單(訂單號:{1})已完成,網站感謝您的支持與配合,歡迎再次光臨。";  
  25.                         break;  
  26.                     default:  
  27.                         break;  
  28.                 }  
  29.  
  30.                 string content = string.Format(template, row["CustomerName"], row["OrderID"]);  
  31.                 SendSMS.Send(row["phone"].ToString(), content);  
  32.             }  
  33.         } 

在項目上線初期,這段代碼工作良好。

在運營一段時間后運營部門同事陸續提出要在某些地方將產品名稱給加上去,在這一改動過程中,我發現代碼沒有和數據相分離,再者如要增加一個訂單狀態后增加相應的短信提示或者取消某一個狀態的短信提示,這個改動過程有點麻煩。于是初步想到將短信的內容放到配置文件中,在調用的時候讀取訂單狀態對應的配置文件然后格式化即可。如讀取的內容為空或者該文件不存在則跳過不發送。主要代碼如下:

  1. v2 內容和數據分離   
  2.  
  3.         #region v2 內容和數據分離   
  4.         static void SendSMS_V2(DataTable dt)  
  5.         {  
  6.             if (null == dt) return;  
  7.  
  8.             for (int i = 0; i < dt.Rows.Count; i++)  
  9.             {  
  10.                 var row = dt.Rows[i];  
  11.                 string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SMSTemplates",  
  12.                     "V2", row["OrderState"].ToString() + ".txt");  
  13.  
  14.                 var template = FileHelper.Read(path);  
  15.                 if (!string.IsNullOrEmpty(template)) {  
  16.                     string content = string.Format(template, row["CustomerName"], row["OrderID"], row["ProductName"]);  
  17.                     SendSMS.Send(row["phone"].ToString(), content);  
  18.                 }  
  19.             }  
  20.         }  
  21.         #endregion 

模版

  1. 尊敬的{0},你好!你的訂單(訂單號:{1})已被確認,請耐心等待。 

隨著運營進行,運營部門不斷地提出將某些字段在某些地方顯示, string.Format 后的參數不斷地增加,每次改后都要將整個過程重新測試一通,很是讓人頭疼!我的想法是開發這邊提供一個數據標簽列表,同時在后臺提供操作界面將短信管理模板讓運營同事自己去修改,不用每次都找我們?有了以上想法,使用一個自定義的 formatter :

  1. 自定義參數格式化   
  2.  
  3.     public class IndexerNamedFormatter : IFormatProvider, ICustomFormatter  
  4.     {  
  5.         public IndexerNamedFormatter() { }  
  6.  
  7.         public object GetFormat(Type formatType)  
  8.         {  
  9.             if (formatType == typeof(ICustomFormatter))  
  10.                 return this;  
  11.  
  12.             throw new TypeAccessException("不匹配的類型。");  
  13.         }  
  14.  
  15.         public string Format(string format, object arg, IFormatProvider formatProvider)  
  16.         {  
  17.             if (null == arg)  
  18.                 throw new ArgumentNullException("參數 arg 不能為 null");  
  19.  
  20.             int indexer = 0;  
  21.             bool isIndexed = int.TryParse(format, out indexer);  
  22.  
  23.             //如是 datarow   
  24.             if (arg is System.Data.DataRow)  
  25.             {  
  26.                 return GetStringFromDataRow(format, arg, indexer, isIndexed);  
  27.             }  
  28.  
  29.             //如是 datareader 之類的  
  30.             if (arg is System.Data.IDataRecord)  
  31.             {  
  32.                 GetStringFromIDataRecord(format, arg, indexer, isIndexed);  
  33.             }  
  34.  
  35.             return string.Empty; ;  
  36.  
  37.         }  
  38.  
  39.         private static void GetStringFromIDataRecord(string format, object arg, int indexer, bool isIndexed)  
  40.         {  
  41.             var dr = (System.Data.IDataRecord)arg;  
  42.             string.Format("{0}", isIndexed ? dr[indexer] : dr[format]);  
  43.         }  
  44.  
  45.         string GetStringFromDataRow(string format, object arg, int indexer, bool isIndexed)  
  46.         {  
  47.             var row = (System.Data.DataRow)arg;  
  48.             return string.Format("{0}", isIndexed ? row[indexer] : row[format]);  
  49.         } 
  1. v3 使用自定義標簽   
  2.  
  3. #region v3 使用自定義標簽   
  4.         static void SendSMS_V3(DataTable dt)  
  5.         {  
  6.             if (null == dt) return;  
  7.  
  8.             IndexerNamedFormatter formatter = new IndexerNamedFormatter();  
  9.             for (int i = 0; i < dt.Rows.Count; i++)  
  10.             {  
  11.                 var row = dt.Rows[i];  
  12.                 string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SMSTemplates",  
  13.                     "V3", row["OrderState"].ToString() + ".txt");  
  14.  
  15.                 var template = FileHelper.Read(path);  
  16.                 if (!string.IsNullOrEmpty(template))  
  17.                 {  
  18.                     string content = string.Format(formatter,  
  19.                         template, row);  
  20.                     SendSMS.Send(row["phone"].ToString(), content);  
  21.                 }  
  22.             }  
  23.         }  
  24.         #endregion 

模版

  1. 尊敬的{0:CustomerName},你好!你的訂單(訂單號:{0:OrderID},產品:產品{0:productname})已被確認,請耐心等待。 

將數據字段取出來后寫成一個標簽列表文檔提供給運營人員后,從此關于這一塊的修改要求安靜了。

以上只是一個小小設計技巧,這也讓我明白需求的準確把握與挖掘是何等地重要!往往客戶今天說要這樣,明天要那樣,大概很多人都在抱怨:你們真麻煩!但在需求不斷地出現時我們是不是在修改的時候也反思下是不是我們未準確把握他們所想要的功能而讓功能設計出了點問題?當然我也不崇尚一開始就大談設計,過度設計要付出大量的時間成本和可能導致實現的復雜度的增加。

一點疑問:

通過查閱文檔我一直感覺 arg is System.Data.DataRow 這種實現方式很是別扭,為什么索引器不定義為一個接口 ?有誰有更好的實現方法麻煩告知,謝謝!

感謝您的閱讀!文中所涉及到的代碼可從此下載

原文鏈接:http://www.cnblogs.com/infozero/archive/2013/03/05/2944106.html

責任編輯:林師授 來源: 博客園
相關推薦

2015-12-04 15:39:27

產品服務反思

2014-09-17 10:30:25

代碼

2021-05-17 11:47:41

多租戶系統私有化

2015-11-02 09:43:25

ASP.NET異步編程

2010-05-20 15:29:43

優化IIS

2009-04-13 11:50:14

經驗交流職業分析面試

2013-05-13 11:25:44

系統架構

2013-05-14 12:06:26

.Net系統架構架構設計

2012-03-27 08:49:19

Json

2009-09-14 19:44:27

LINQ To SQL

2009-07-09 15:09:05

JDK卸載

2009-07-22 14:53:45

ibmdwIT架構

2025-05-29 00:00:00

UI 庫前端模塊化

2016-04-05 10:12:58

HiveSQLHadoop

2024-05-31 08:40:09

2016-01-06 09:49:59

青云/SDN

2009-09-14 20:17:05

并行LINQ

2014-06-04 10:48:38

Swift蘋果iOS

2012-07-12 10:49:53

項目管理

2011-07-04 09:33:04

惠普轉型李艾科
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美国产日韩在线 | 免费av在线网站 | 日本又色又爽又黄又高潮 | 欧美一区二区三区在线免费观看 | 91久久国产综合久久 | 欧洲精品码一区二区三区免费看 | 在线播放中文字幕 | 久久只有精品 | 久久久精品久久久 | wwwxxx国产| 国产精品日韩欧美一区二区 | 亚洲精品电影在线观看 | 91资源在线| 午夜在线观看视频 | 在线电影日韩 | 中文字幕免费观看 | 夜夜夜久久久 | 午夜免费网站 | 中文字幕第100页 | 亚洲www啪成人一区二区麻豆 | 国产免费一区二区三区 | 日本欧美在线视频 | 一级黄在线观看 | 色吧综合| 久久久久欧美 | 亚洲一区视频 | 精品久久久久久久久久久久 | 亚洲高清在线视频 | 男女啪啪高潮无遮挡免费动态 | 热99精品视频 | 一级免费在线视频 | 国产专区免费 | av一区在线| 亚洲福利一区 | 激情六月丁香婷婷 | 久久999 | 日日日色 | 日韩午夜激情 | 久久久久一区二区 | 视频一区二区国产 | 国产一区二区三区免费观看在线 |