2025-03-24

 從2006年-2012年,在全國計算機技術與軟件專業技術資格(水平)考試軟件設計師級別考試中,狀態模式已兩次作為下午試題的最後一題出現(參考:歷年軟件設計師下午考試試題匯總統計),分別是2006年下半年和2011年下半年的兩次考試。

 

【全國計算機技術與軟件專業技術資格(水平)考試  2006 年下半年 軟件設計師 下午試卷】

       註:當年試題六和試題七二選一,試題六為C++版,試題七為Java版。

 

       試題六

       閱讀以下說明和 C++代碼,將應填入 (n) 處的字句寫在答題紙的對應欄內。

       【說明】

       傳輸門是傳輸系統中的重要裝置。傳輸門具有 Open(打開)、Closed(關閉)、Opening(正在打開)、StayOpen(保持打開)、Closing(正在關閉)五種狀態。觸發傳輸門狀態轉 換的事件有 click、complete 和 timeout 三種。事件與其相應的狀態轉換如圖6-1 所示。

 圖6-1  傳輸門響應事件與其狀態轉換圖

       下面的【C++代碼 1】與【C++代碼 2】分別用兩種不同的設計思路對傳輸門進行狀態模擬,請填補代碼中的空缺。

 

【C++代碼 1】

const  int  CLOSED  =  1;  const  int  OPENING  =  2;

const  int  OPEN  =  3; const  int  CLOSING  =  4;

const  int  STAYOPEN  =  5;    //定義狀態變量,用不同整數表示不同狀態

 

class  Door  {

    private:

    int  state; //傳輸門當前狀態

    void  setState(int  state){ this->state  =  state;  }  //設置當前狀態

    public: Door():state(CLOSED){};

    void  getState() {       //根據當前狀態輸出相應的字符串

        switch(state) {

            case  OPENING:  cout  <<"OPENING" <<  endl; break;

            case  CLOSED:  cout  <<  "CLOSED" <<  endl; break;        

            case  OPEN:  cout  <<  "OPEN" <<  endl;  break;

            case  CLOSING: cout  <<  "CLOSING" <<  endl; break;

            case  STAYOPEN:  cout  <<  "STAYOPEN" <<  endl;  break;

        }

    }

 

    void  click()  {        //發生click事件時進行狀態轉換

        if  ((1) )   setState(OPENING);

        else  if  ((2) ) setState(CLOSING);

        else  if  ((3) ) setState(STAYOPEN);

    }

 

    void  timeout(){        //發生timeout事件時進行狀態轉換

        if  (state  ==  OPEN)  setState(CLOSING);

    }

 

    void  complete(){       //發生complete事件時進行狀態轉換

        if  (state  ==  OPENING)    setState(OPEN);

        else  if  (state  ==  CLOSING)    setState(CLOSED);

    }

};

 

int  main() {

    Door  aDoor;

    aDoor.getState();  

    aDoor.click(); 

    aDoor.getState();  

    aDoor.complete();

    aDoor.getState();                   

    aDoor.click(); 

    aDoor.getState();  

    aDoor.click();

    aDoor.getState();  

    return  0;

}

 

【C++代碼 2】

class  Door  {

    public:

    DoorState  *CLOSED,  *OPENING,  *OPEN,  *CLOSING,  *STAYOPEN,  *state;

    Door();

    virtual  ~Door(){  ……  //釋放申請的內存,此處代碼省略};

    void  setState(DoorState  *state)  {   this->state  =  state; }

    void  getState(){

        //  此處代碼省略,本方法輸出狀態字符串,

        //  例如,當前狀態為CLOSED時,輸出字符串為“CLOSED”

    }

    void  click();

    void  timeout();

    void  complete();

};

 

 

Door::Door() {

    CLOSED  =  new DoorClosed(this);

    OPENING  =  new DoorOpening(this);

    OPEN  =  new DoorOpen(this);

    CLOSING  =  new DoorClosing(this);

    STAYOPEN  =  new DoorStayOpen(this); 

    state  =  CLOSED;

}

void  Door::click() {   (4) ;}

void  Door::timeout() {   (5) ; }

void  Door::complete() {(6) ; }

 

class  DoorState { //定義一個抽象的狀態,它是所有狀態類的基類

    protected:  Door  *door;

    public:

    DoorState(Door  *door)  {  this->door  =  door;  }

    virtual  ~DoorState(void);

    virtual  void  click()  {}

    virtual  void  complete()  {}

    virtual  void  timeout()  {}

};

 

class  DoorClosed  :public  DoorState{  //定義一個基本的 Closed 狀態

    public:

    DoorClosed(Door  *door):DoorState(door)  {}

    virtual  ~ DoorClosed  (){}

    void  click();

};

 

void  DoorClosed::click()  {(7) ; }

//  其它狀態類的定義與實現代碼省略

 

int  main() {

    Door  aDoor;

    aDoor.getState(); aDoor.click();   aDoor.getState(); aDoor.complete();

    aDoor.getState(); aDoor.timeout(); aDoor.getState(); return  0;

}

 

     試題七

       閱讀以下說明以及Java程序,將應填入 (n)  處的字句寫在答題紙的對應欄內。

       【說明】

傳輸門是傳輸系統中的重要裝置。傳輸門具有 Open(打開)、Closed(關閉)、Opening(正在打開)、StayOpen(保持打開)、Closing(正在關閉)五種狀態。觸發狀態的轉換事件有 click、complete 和 timeout 三種。事件與其相應的狀態轉換如圖7-1所示。

  

圖7-1  傳輸門響應事件與其狀態轉換圖

       下面的【Java 代碼 1】與【Java 代碼 2】分別用兩種不同的設計思路對傳輸門進行狀態模擬,請填補代碼中的空缺。

【Java代碼 1】

public  class  Door  {

    //定義狀態變量,用不同的整數表示不同狀態

    public static final int CLOSED = 1;

    public static final int OPENING = 2;

    public static final int OPEN  = 3;

    public static final int CLOSING = 4;

    public static final int STAYOPEN = 5;  

    private  int  state  =  CLOSED;

 

    private void setState(int state){this.state  =  state;} //設置傳輸門當前狀態

    public  void  getState() {

        //  此處代碼省略,本方法輸出狀態字符串,

        //  例如,當前狀態為 CLOSED 時,輸出字符串為”CLOSED”

    }

    public  void  click()  {   //發生 click 事件時進行狀態轉換

        if  ((1) )   setState(OPENING);

        else  if  (   (2)     )  setState(CLOSING);

        else  if  ((3) )    setState(STAYOPEN);

    }

 

    //發生 timeout 事件時進行狀態轉換

    public  void  timeout() {    if  (state  ==  OPEN)  setState(CLOSING); }

 

    public  void  complete() { //發生 complete 事件時進行狀態轉換

        if  (state  ==  OPENING)   setState(OPEN);

        else  if  (state  ==  CLOSING)    setState(CLOSED);

    }

 

    public  static  void  main(String  []  args){

        Door  aDoor  =  new Door();

       aDoor.getState(); aDoor.click(); aDoor.getState(); aDoor.complete(); aDoor.getState(); aDoor.click();     aDoor.getState(); aDoor.click(); aDoor.getState(); return;

    }

}

 

【Java代碼 2】

public  class  Door  {

    public  final  DoorState  CLOSED  =  new DoorClosed(this);

    public  final  DoorState  OPENING  =  new DoorOpening(this);

    public  final  DoorState  OPEN  =  new DoorOpen(this);

    public  final  DoorState  CLOSING  =  new DoorClosing(this);

    public final DoorState STAYOPEN  =  new DoorStayOpen(this);

    private  DoorState  state  =  CLOSED;

 

//設置傳輸門當前狀態

    public void setState(DoorState state){ this.state = state;}

    public  void  getState(){  //根據當前狀態輸出對應的狀態字符串

        System.out.println(state.getClass().getName());

    }

    public  void  click() {   (4) ;}//發生 click 事件時進行狀態轉換

    public  void  timeout() {     (5) ;}//發生 timeout 事件時進行狀態轉換

    public  void  complete() {   (6) ;}//發生 complete 事件時進行狀態轉換

 

    public  static  void  main(String[]  args){

        Door  aDoor  =  new Door();

        aDoor.getState(); aDoor.click();   aDoor.getState(); aDoor.complete();

        aDoor.getState(); aDoor.timeout(); aDoor.getState(); return;

    }

}

 

public  abstract  class  DoorState  {  //定義所有狀態類的基類

    protected  Door  door  ;

    public  DoorState(Door  door)  {this.door  =  door;}

    public  void  click()  {} public   void  complete()  {} public  void  timeout()  {}

}

 

class  DoorClosed  extends  DoorState{  //定義一個基本的 Closed 狀態

    public  DoorClosed(Door  door)  {    super(door);  }

    public  void  click()  {     (7) ;   }

    //該類定義的其餘代碼省略

}

//其餘代碼省略

 

 ——————————————————————————————————————————————————

 

    解答:

      本題前三空的難度不大,隻要能夠看懂狀態圖並讀懂代碼,正確填寫應該沒有太大問題,後四空略有難度,特別是最後一空。在本試題中提供瞭兩種狀態轉換實現方案:

      【方案一】(即代碼一)沒有用狀態模式,將所有的狀態轉換代碼都寫到Door類中,每一個狀態對應一個整型常量(狀態變量),當Door的click()等方法被調用時,可以實現相應狀態的轉換,根據狀態圖,可以完成對(1)、(2)和(3)空的解答,例如當狀態變量state為CLOSED或者CLOSING時,調用click()方法,狀態將轉換為OPENING。同理,當timeout()方法和complete()方法被調用時,某些狀態之間也可以發生轉換。

      【方案二】(即代碼二)使用瞭狀態模式,Door類充當環境類,提供瞭抽象類DoorState充當抽象狀態類,其子類,如DoorClosed、DoorOpening等,充當具體狀態類。在環境類Door枚舉瞭所有的狀態,提供瞭一個setState()方法用於設置當前狀態,此外,在Door的click()方法中調用狀態類的click()方法,在Door的timeout()方法中調用狀態類的timeout()方法,在Door的complete()方法中調用狀態類的complete()方法。因此,(4)、(5)、(6)空用於實現間接調用。第(7)空用於實現狀態的切換,當狀態為DoorClosed時,如果調用click()方法,那麼Door的當前狀態將切換到OPENING,因此在第(7)空,將調用door對象的setState()方法,註入一個DoorOpening類型的對象,由於該對象已存在於Door中,無須再重新創建。在C++中,可以通過door->OPENING來獲取,而在Java中則通過door.OPENING來獲取。在本試題中,狀態的切換由具體狀態類來完成,由環境類來維護各個具體狀態類的實例。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *