久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

策略模式的應用實踐

 ljjzlm 2006-08-04

策略模式的應用實踐

Filed under: — bruce zhang @ 5:11 pm

在工作中,我需要寫一個話單轉換工具,,在寫這個工具的過程中,,發(fā)現整個實現恰恰可以說是策略模式最好的體現。用這個例子來說明策略模式的應用,,最合適不過了,。

話單轉換工具的目的:將某個服務提供商的話單文本文件,轉換為另一個服務提供商的話單文本文件,。如將聯(lián)通的話單格式轉換為移動的話單格式,。

話單轉換工具的要求:能夠實現多個服務提供商話單文本文件的互相轉換。

我們首先來分析一下任務,。首先,,各種服務提供商的話單格式,無疑是不相同的,。例如,,話單采集后,,字段的順序,字段的寬度以及字段間的分割符,,都不相同,。但是,從總體上來說,,話單的表現形式是大致相同的,這位我們實現話單轉換提供了一個技術上可行的前提,。

所謂話單轉換,,就是需要將一個話單文本文件讀出,然后對每一行的字符串進行識別后,,再轉換為符合相對應的服務提供商標準的話單文本文件,。操作很簡單,就是文本文件的讀寫而已,,不同的就在于轉換的方法,。根據服務提供商標準的不同,我們應該為每一種轉換提供相對應的算法,。而所謂策略模式,,正是對算法的包裝和抽象,將算法的責任和其本身分離,。所以,,我們現在要做的工作就是將轉換話單的算法抽象出來。

根據工具的要求,,話單轉換應該包括3個方法:
1,、將文件讀出的一行字符串轉換為對應的話單對象;
2,、將一種話單對象轉換為另一種話單對象,;
3、將話單對象轉換為字符串,,以方便寫入話單文本文件,;

根據以上的分析,我們還需要為不同的話單格式建立相應的對象,。例如:網通,、聯(lián)通和移動的話單格式對象分別為:
public class CNCCdr
{
 //網通話單格式對象的公共屬性;
}
public class CUCCdr
{
 //聯(lián)通話單格式對象的公共屬性,;
}
public class CMCdr
{
 //移動話單格式對象的公共屬性,;
}

接下來就應該實現話單轉換的算法了。首先需要將算法進行抽象,,而進行抽象的最佳選擇莫過于使用接口,,例如我們定義一個用于話單轉換的接口ICdrConvert:
public interface ICdrConvert
{
}
按照如前的分析,,在接口中應該包括三個轉換方法。但是現在有個問題,,就是轉換的話單對象,。由于方法在接口中,為一個抽象,。而話單對象可能有多種,,具體轉換為何種話單對象,需要到具體實現時才能決定,。因此,,在接口方法中,無論返回類型,,還是傳入參數,,涉及到的話單對象只能是抽象的。也許我們可以考慮System.Object來表示話單對象,,但更好的辦法是為所有的話單對象也提供一個抽象接口,。

由于從目前的分析來看,抽象話單對象并沒有一個公共的方法,,所以這個抽象的話單接口,,是一個標識接口:
public interface ICdrRecord
{
}

現在,可以對轉換接口的方法進行定義了:
public interface ICdrConvert
{
 ICdrRecord Convert(string record);
 ICdrRecord Convert(ICdrRecord record);
 string Convert(ICdrRecord record);
}

自然,,這樣的接口定義無法通過編譯,。為什么呢?是因為第二個方法的簽名與第三個方法的簽名重復了(方法的簽名和返回類型無關),。因此,,我們需要為第三個方法修改名字。

但我們仔細想想,,第三個方法的轉換在轉換接口中是必要的嗎,?該方法的任務是將一個話單對象轉換為string類型。實際上這個責任,,并不需要專門的轉換對象來完成,,而應屬于話單對象本身的責任。再想想.Net中,,所有對象均派生于System.Object,,而object類型均提供了ToString()方法。

從設計的角度來看,,最好的辦法,,是在具體的話單對象中override System.Object的ToString()方法,而不是在轉換對象中,,提供該轉換算法,。

不過考慮到,,在話單處理中,更多地會調用抽象話單接口類型的對象,,也許我們將ToString()方法抽象到接口ICdrRecord中會更好,。
public interface ICdrRecord
{
 string ToString();
}
public interface ICdrConvert
{
 ICdrRecord Convert(string record);
 ICdrRecord Convert(ICdrRecord record);
}
而具體的話單對象,就應該實現ICdrRecord接口了,。因為各話單對象均繼承了System.Object,,則間接地繼承了object對象的ToString()方法,所以,,話單對象應該重寫該方法:
public class CNCCdr: ICdrRecord
{
 //網通話單格式對象的公共屬性,;

 //重寫object的ToString()方法,同時也實現了接口ICdrRecord的ToString()方法,;
 public override string ToString()
 {
  //實現具體的內容;
 }
}
public class CUCCdr: ICdrRecord
{
 //聯(lián)通話單格式對象的公共屬性,;

 //重寫object的ToString()方法,,同時也實現了接口ICdrRecord的ToString()方法;
 public override string ToString()
 {
  //實現具體的內容,;
 }
}
public class CMCdr: ICdrRecord
{
 //移動話單格式對象的公共屬性,;

 //重寫object的ToString()方法,同時也實現了接口ICdrRecord的ToString()方法,;
 public override string ToString()
 {
  //實現具體的內容,;
 }
}

下面就是關鍵的實現了。由于我們已經為轉換算法進行了抽象,,因此根據策略模式來實現具體的轉換算法,,就是水到渠成的事情了。實現代碼之前,,先來看看UML類圖:

tragedy.gif

注意看橙色部分,,這一部分即為策略模式的主體。接口ICdrConvert為抽象策略角色,,類CNCToCUC,,CUCToCM為具體策略角色,它們分別實現了將網通話單轉換為聯(lián)通話單,,聯(lián)通話單轉換為中國移動話單的算法,。根據實際需要,還可以添加多個類似的具體策略角色,,并實現ICdrConvert接口:
public class CNCToCUC:ICdrConvert
{
 public ICdrRecord Convert(string record)
 {
  //實現具體的轉換算法,;
 }
 public ICdrRecord Convert(ICdrRecord record)
 {
  //實現具體的轉換算法;
 }
}
類CUCToCM的實現相似,,不再重復,。

那么通過策略模式實現,,究竟有什么好處呢?請大家注意上圖的CdrOp類,。該類是抽象類,,它提供了一個構造函數,可以傳遞ICdrConvert對象:
public abstract class CdrOp
{
 protected ICdrConvert _convert;
 protected string _sourceFileName;
 protected string _targetFileName;
 
 public CdrOp(string soureFileName,string targetFileName,ICdrConvert convert)
 {
  _sourceFileName = soureFileName;
  _targetFileName = targetFileName;
  _convert = convert;
 }

 public abstract void HandleCdr(); 
}

類CdrFileOp繼承了抽象類CdrOp:
public class CdrFileOp
{
 public override void HandleCdr()  
 {
  Read();
  Write();
 }
 
 private string Read()
 {
  using (StreamReader sd = new StreamReader(_sourceFileName))
  { 
   ICdrRecord cdr = null; 
   string line;
   while ((line = sd.ReadLine()) != null)
   {
    //首先調用ICdrRecord Convert(string record)方法,;
    //再調用ICdrRecord Convert(ICdrRecord record)方法,;
    //至于實現的是何種轉換,由構造函數傳入的ICdrConvert對象決定,;
    cdr = _convert.Convert(_convert.Convert(line));
    _list.Add(cdr);      
   }
  }
 }

 private void Write()
 {
  using (StreamWriter sw = new StreamWriter(_targetFileName,true))
  {    
   sw.Write(head.ToString());
   foreach (ICdrRecord record in _list)
   {
    sw.Write(record.ToString());
   }
  }
 }

 private ArrayList _list = new ArrayList();
}

這個類,,實現了抽象類CdrOp的HandleCdr()方法。但具體的實現細節(jié)則是在私有方法Read()和Write()中完成的(根據實際情況,,也可以把Read和Write方法作為公共抽象方法或保護方法,,放到抽象類CdrOp中,而在抽象類CdrOp中具體提供HandleCdr方法的實現,,該方法調用Read和Write方法,,這樣就使用了模版方法模式)。

注意看Read和Write方法中,,沒有一個具體類,。不管是話單對象,還是話單轉換對象,,均是抽象接口對象,。尤其是在Read()方法中,調用了_Convert的Convert方法:
cdr = _convert.Convert(_convert.Convert(line));
內部的Convert方法,,即_convert.Convert(line),,是將讀出來的字符串轉換為ICdrRecord對象,然后通過調用_convert.Convert(ICdrRecord record)方法,,再將該對象轉換為另一種話單格式對象,,但類型仍然屬于ICdrRecord。

那么在這些轉換過程中,,究竟轉換成了哪一種話單格式對象呢,?這是由_convert字段來決定的。而這個對象則是由構造函數的參數中傳遞進來的,。

同樣的道理,,在Write()方法中,大家也可以看到為所有話單對象抽象為一個接口ICdrRecord的好處,。通過ICdrRecord調用ToString()方法,,避免了在CdrFileOp中引入具體對象。要知道,,程序一旦引入具體對象,,則耦合性就高了,。一旦需求發(fā)生改變,就需要對編碼進行修改,。

有了以上的架構,,客戶端調用就非常方便了:
public class Client
{
 public static void Main()
 {
  string sourceFileName = “c:\CNCCdr.txt”;
  string target1= “c:\CUCCdr.txt”;
  string target2= “c:\CMCdr.txt”;
  
  //將網通話單轉換為聯(lián)通話單;
  ICdrOp op1 = new CdrFileOp(sourceFileName,target1,new CNCToCUC());
  op1.HandleCdr();

  //將剛才轉換生成的聯(lián)通話單轉換為移動話單,;
  ICdrOp op2 = new CdrFileOp(target1,target2,new CUCToCM());
  op2.HandleCdr();  
 }
}

當然,,我們還可以引入工廠模式來創(chuàng)建CdrFileOp對象?;蛘邔CdrConvert對象設置為CdrFileOp的公共屬性,,而非通過構造函數來傳入。然而,,通過本文,,策略模式的精要已經體現得淋漓盡致了。

    本站是提供個人知識管理的網絡存儲空間,,所有內容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內容中的聯(lián)系方式,、誘導購買等信息,謹防詐騙,。如發(fā)現有害或侵權內容,,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多