程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Design Patterns: Solidify Your C# Application Arch

Design Patterns: Solidify Your C# Application Arch

編輯:關於C語言
【譯序:C#進階文章。譯者對Samir提供的C#例子進行了簡單整理(作者提供的某些代碼在譯者的環境中無法通過編譯),並編寫了對應的C++示例,一並置於譯注中,以便讀者比對。譯文中所有C#、C++程序調試環境均為Microsoft Visual Studio.Net 7.0 Beta2】

C++示例:

#include "stdafx.h";

#include <iOStream>

#include <list>

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<<"Drawing a line"<<endl;

     }

};

class Circle : public Shape

{

private:

     double x, y, r;

public:

     Circle(double x, double y, double radius)

     {

          this->x = x;

          this->y = y;

          this->r = r;

     }

     void Draw()

     {

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

          cout<<"Drawing a circle"<<endl;

     }

};

class Drawing : public Shape

{    

private:

     list<Shape*> shapes;

     list<Shape*>::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<Shape*>(*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

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

     基於表查找的方式是有限狀態機的一個流行的設計方式。一個表映射了所有可能的輸入到狀態轉換(即可能會導致有限狀態機變換到另一個狀態的轉換)。不用說,盡管這種方式比較簡單,但如果不對現有的實現代碼作重大修改的話,是不可能適應變化的需求的。一個更好的替代方案是使用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 override 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模式優於簡單的、基於表查找的實現方式。總之,這種設計模式有助於將狀態細節行為局部化於實現具體狀態的類中,因此促進了軟件的重用和擴展。這也避免了在程序代碼中四處亂寫條件語句的需要,而那將使維護代碼的程序員苦不堪言,現實中,這些負責維護的程序員的人數遠遠多於最初的實現者。
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved