我們在寫一些程式的時候,偶爾會遇到因為不同選項需要使用不同的程式,例如說需要設計給不同客戶的程式,主程式不變,但是處理的程序不同,以前的做法就是直接使用switch的方式來設計,但是一旦選項多起來,程式就非常的難以維護。

雖然這個方法在C++裏面是很普通的方式,但是如果不是一直研究程式寫法的話,往往不知道怎麼寫這樣的程式碼,只好用傳統的方法一直痛苦下去。

舉例而言,類神經網路有兩種轉換函數,Sigmoid值域是0到1之間,而HyperTan值域是在-1到+1之間,我們可以宣告一個列舉(枚舉)隨便啦就是enum,然後用switch來處理。但是如果用的地方比較多,程式碼就會有很多多餘的switch需要判斷,不但寫起來痛苦,程式維護也很難過。

   1: public enum TransferMethodTypes { Sigmoid, HyperTan }
   2: public class NetworkFunctions {
   3:  
   4:     public NetworkFunctions(TransferMethodTypes transferType) {
   5:         switch (transferType) {
   6:             case TransferMethodTypes.Sigmoid:
   7:                 _transfer = TransferSigmoid;
   8:                 _diffent = DiffentSigmoid;
   9:                 break;
  10:             case TransferMethodTypes.HyperTan:
  11:                 _transfer = TransferHyperTan;
  12:                 _diffent = DiffentHyperTan;
  13:                 break;
  14:         }
  15:     }
  16:  
  17:     #region "Tranfer Function"
  18:  
  19:     /// <summary>
  20:     /// 網路轉換函數
  21:     /// </summary>
  22:     /// <param name="value">網路輸出值</param>
  23:     /// <returns>轉換值</returns>
  24:     public delegate double TransferFunctionHandler(double value);
  25:     private TransferFunctionHandler _transfer;
  26:     public TransferFunctionHandler Transfer { get { return _transfer; } }
  27:  
  28:     private double TransferSigmoid(double value) {
  29:         return (double)(1.0 / (1.0 + Math.Exp(-value)));
  30:     }
  31:  
  32:     private double TransferHyperTan(double value) {
  33:         return (double)(1.0 / (1.0 + Math.Exp(-value)));
  34:     }
  35:  
  36:     #endregion
  37:  
  38:     #region "Diffent Function"
  39:  
  40:     /// <summary>
  41:     /// 差異值函數
  42:     /// </summary>
  43:     /// <param name="diffentValue">差異值</param>
  44:     /// <param name="outputValue">輸出值</param>
  45:     /// <returns>差異值</returns>
  46:     public delegate double DiffentFunctionHandler(double diffentValue, double outputValue);
  47:     private DiffentFunctionHandler _diffent;
  48:     public DiffentFunctionHandler Diffent { get { return _diffent; } }
  49:  
  50:     const double d = 0.01;
  51:     private double DiffentSigmoid(double diffvalue, double outvalue) {
  52:         // Y(1-Y)(T-Y) = o * (1-o) * d
  53:         return (outvalue * (1.0 - outvalue) + d) * diffvalue;
  54:     }
  55:     private double DiffentHyperTan(double diffvalue, double outValue) {
  56:         // (1+Y)(1-Y)(T-Y) = (1-o) * (1+o) * d
  57:         return ((1.0 + outValue) * (1.0 - outValue) + d) * diffvalue;
  58:     }
  59:  
  60:     #endregion
  61:  
  62: }

 

第一行宣告一個列舉,應該不是問題。第二行就宣告一個類,這個類的創建函數就是傳入這個列舉的選項,然後根據選項綁定對應的方法到這個類的變數上。

第24行,宣告一個委託,委託其實就是一個類的特例,你可以把它當成是一個方法結構的定義。

第25行,宣告一個變數,用來綁定相對應的方法。

第26行,宣告一個唯獨的屬性,讓外部來使用所綁定的方法。

第27行,就是每一種方法的實例。

   1: netfunc = new NetworkFunctions(args.TransferType);
   2:  
   3: this.cells[layerNo][cellNo].Result = netfunc.Transfer(value);
   4: this.cells[layerNo][cellNo].Diffent = 
   5:     netfunc.Diffent(sumdiff, this.cells[layerNo][cellNo].Result);

 

之後你就可以使用第1行的方式創建一個類實例,並且傳入你的選項,接著只要專注在主程式的撰寫就好了。這樣的寫法程式完全集中起來,維護上也不會有痛苦了。

創作者介紹

人生四十宅開始 二號宅

漠哥 發表在 痞客邦 留言(0) 人氣()