Design Patterns: Solidify Your C# Application Architecture with Design Patterns中文版(下篇) (轉)

worldblog發表於2007-12-11
Design Patterns: Solidify Your C# Application Architecture with Design Patterns中文版(下篇) (轉)[@more@]

Design Patterns: Solidify Your Application Architecture with Design Patterns中文版(下篇):namespace prefix = o ns = "urn:schemas--com::office" />

作者:Samir Bajaj

譯者:榮耀

【譯序:C#進階文章。譯者對Samir提供的C#例子進行了簡單整理(作者提供的某些程式碼在譯者的環境中無法透過編譯),並編寫了對應的C++示例,一併置於譯註中,以便讀者比對。譯文中所有C#、C++環境均為Microsoft 7.0 Beta2】

C++示例:

#include "stdafx.h";

#include

#include

using namespace std;

class Shape

{

public:

  virtual void Draw(){};

};

class Line : public Shape

{

private:

  double x1, y1, x2, y2;

public:

  Line(double x1, double y1, double x2, double y2)

  {

    this->x1 = x1;

    this->y1 = y1;

    this->x2 = x2;

    this->y2 = y2;

  }

  void Draw()

  {

  //從(x1, y1) 到(x2, y2)畫一條線

    cout<

  }

};

class Circle : public Shape

{

private:

  double x, y, r;

public:

  Circle(double x, double y, double )

  {

    this->x = x;

    this->y = y;

    this->r = r;

  }

  void Draw()

  {

  //以(x, y)為圓心,r為半徑畫一個圓

    cout<

  }

};

class Drawing : public Shape

private:

  list shapes;

  list::iterator it;

public:

  Drawing()

  {

  }

  ~Drawing()

  {

  for (it = shapes.begin(); it != shapes.end(); it++)

  {

  if (*it)

  {

    delete *it;

    *it = NULL;   

  }

  }

    shapes.clear();

  }

  void Add(Shape* s)

  {

    shapes.push_back(s);

  }

  void Draw()

  {

  for (it = shapes.begin(); it != shapes.end(); it++)

  {

    (dynamic_cast(*it))->Draw();

  }

  }

};

int _tmain(int argc, _TCHAR* argv[])

{

  Line* line = new Line(0, 0, 10, 12);

  Circle* circle = new Circle(2, 3, 5.5); 

  Drawing* dwg = new Drawing();

  dwg->Add(new Line(3, 4, 3, 5));

  dwg->Add(new Circle(5, 6, 7.7));

  Shape* array[3] = {line, circle, dwg};

  // 畫出所有的圖形,注意:用一致的方式來訪問所有

  for (int i = 0; i < 3; ++i)

  {

    array[i]->Draw();

  delete array[i];

  } 

  return 0;

}

/*以下是程式輸出結果:

Drawing a line

Drawing a circle

Drawing a line

Drawing a circle

*/

state

  每一位開發人員在他(她)的職業生涯裡都至少實現過一次有限狀態機。你無法躲避它們,它們無處不在,並且並不僅僅侷限於開發領域。關於確定性有限自動機的設計和實現方面的文獻隨處可見也是不足為奇的。談到有限狀態機,我常常驚訝地看到設計上糟糕的、實現上充滿的、根本不考慮擴充套件性的案例。可以向有限自動機中加入更多狀態的能力通常是不成文的要求。當需要加入更多的狀態和轉換時,常常需要修改實現。如果設計良好,你就能夠預見和處理這種變化。更重要的是,有限狀態機中的任何狀態的行為和操作細節都只應該被限制於對該狀態的表示上。換句話說,狀態細節程式碼應該駐留在實現該狀態的物件裡,這就易於加入新狀態並易於轉換。

  基於表查詢的方式是有限狀態機的一個流行的設計方式。一個表對映了所有可能的輸入到狀態轉換(即可能會導致有限狀態機變換到另一個狀態的轉換)。不用說,儘管這種方式比較簡單,但如果不對現有的實現程式碼作重大修改的話,是不可能適應變化的需求的。一個更好的替代方案是使用state設計。

  假設用軟體來實現一個碳酸飲料自動販賣機,這個機器只接受5分、10分和25分的硬幣,當投幣分值累積到或超過25分時,即發出一罐飲料。每一次向槽內投入硬幣,都會導致自動販賣機轉換到一個不同的狀態,直到投幣數達到所需的數量,此時機器會發出一罐飲料並重置回Start狀態。表10程式碼定義了一個抽象類State,它代表自動販賣機所能變換的所有狀態的基類。

表10

abstract class State

{

public virtual void AddNickel(VendingMachine vm){ }

public virtual void AddDime(VendingMachine vm){ }

public virtual void AddQuarter(VendingMachine vm){ }

  protected virtual void ChangeState(VendingMachine vm, State s)

  {

  vm.ChangeState(s);

  }

}

  所有5個狀態都從該基類派生並過載相應的虛方法。例如,當自動販賣機處於Start狀態時,投入一個5分硬幣,則機器變為Five狀態,如果再投入一個5分硬幣,則切換為Ten狀態。這就把轉換邏輯分離到每一個實現狀態的物件中。表11展示了實現狀態的兩個類。

表11

class Start : State

{

  private static State state = new Start();

  private Start()

  {

  }

  public static State Instance()

  {

  // singleton邏輯

  Console.WriteLine("Credit: 0c");

  return state;

  }

  public overr void AddNickel(VendingMachine vm)

  {

  ChangeState(vm, Five.Instance());

  }

  public override void AddDime(VendingMachine vm)

  {

  ChangeState(vm, Ten.Instance());

  }

  public override void AddQuarter(VendingMachine vm)

  {

  vm.Vend();

  }

}

class Five : State

{

   private static State state = new Five();

  private Five()

  {

  }

  public static State Instance()

  {

  // singleton邏輯

  Console.WriteLine("Credit: 5c");

  return state;

  }

  public override void AddNickel(VendingMachine vm)

  {

  ChangeState(vm, Ten.Instance());

  }

  public override void AddDime(VendingMachine vm)

  {

  ChangeState(vm, Fifteen.Instance());

  }

  public override void AddQuarter(VendingMachine vm)

  {

  vm.Vend();

  ChangeState(vm, Start.Instance()); // no change returned :-)

  }

}

  自動販賣機不必關心狀態轉換邏輯,它只管用當前state例項進行操作,這樣,就徹底和有關狀態細節解耦。參見表12。

表12

class VendingMachine

{

  private State state;

  public VendingMachine()

  {

  Console.WriteLine("The Vending Machine is now online: product costs 25c");

  state = Start.Instance();

  }

  public void ChangeState(State to)

  {

  state = to;

  }

  public void Vend()

  {

  // 發飲料

  Console.WriteLine("Dispensing product...Thank you!");

  }

  public void AddNickel()

  {

  state.AddNickel(this);

  }

  public void AddDime()

  {

  state.AddDime(this);

  }

  public void AddQuarter()

  {

  state.AddQuarter(this);

  }

}

  我已經說明了state模式優於簡單的、基於表查詢的實現方式。總之,這種設計模式有助於將狀態細節行為區域性化於實現具體狀態的類中,因此促進了軟體的重用和擴充套件。這也避免了在程式程式碼中四處亂寫條件語句的需要,而那將使維護程式碼的程式設計師苦不堪言,現實中,這些負責維護的程式設計師的人數遠遠多於最初的實現者。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-991476/,如需轉載,請註明出處,否則將追究法律責任。

相關文章