成人免费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

代碼

2015-11-02 09:43:25

ASP.NET異步編程

2021-05-17 11:47:41

多租戶系統私有化

2010-05-20 15:29:43

優化IIS

2013-05-13 11:25:44

系統架構

2013-05-14 12:06:26

.Net系統架構架構設計

2009-04-13 11:50:14

經驗交流職業分析面試

2012-03-27 08:49:19

Json

2009-07-09 15:09:05

JDK卸載

2009-09-14 19:44:27

LINQ To SQL

2009-07-22 14:53:45

ibmdwIT架構

2025-05-29 00:00:00

UI 庫前端模塊化

2016-04-05 10:12:58

HiveSQLHadoop

2009-09-14 20:17:05

并行LINQ

2014-06-04 10:48:38

Swift蘋果iOS

2012-07-12 10:49:53

項目管理

2024-05-31 08:40:09

2011-07-04 09:33:04

惠普轉型李艾科

2016-01-06 09:49:59

青云/SDN
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 99热这里都是精品 | 国产毛片毛片 | 久久国产一区二区三区 | 国产成人精品一区二区三区四区 | 中文字幕一区二区三区不卡 | 精品视频久久久久久 | 人人人艹| 99日韩 | 免费在线观看一区二区 | 午夜精品久久久久99蜜 | 亚洲+变态+欧美+另类+精品 | 亚洲精品68久久久一区 | 精品国产视频 | 草草影院ccyy | 欧美成人一区二免费视频软件 | 电影91久久久 | 看av电影 | 欧美午夜一区二区三区免费大片 | 日韩在线不卡视频 | 国产精品视频一区二区三区, | 亚洲精品免费在线观看 | 欧美一二三区 | 91精品国产综合久久精品 | 久久久久91 | 一级国产精品一级国产精品片 | 国产高清在线精品一区二区三区 | 337p日韩 | 亚洲精品一区二区在线观看 | 国产黄色av网站 | 亚洲精品一区二区三区在线观看 | 欧美99 | 成人特区 | 免费在线色| 国产精品久久久久久久久图文区 | 国产伦精品一区二区三区视频金莲 | 国产精品久久精品 | 亚洲狠狠 | 黄色av网站在线观看 | 久久一区二区视频 | 亚洲天堂影院 | 视频在线亚洲 |