设计模式与软考试题之状态模式(一)

      从2006年-2012年,在全国计算机技术与软件专业技术资格(水平)考试软件设计师级别考试中,状态模式已两次作为下午试题的最后一题出现(参考:历年软件设计师下午考试试题汇总统计),分别是2006年下半年和2011年下半年的两次考试。

 

【全国计算机技术与软件专业技术资格(水平)考试  2006 年下半年 软件设计师 下午试卷】

 

       注:当年试题六和试题七二选一,试题六为C++版,试题七为Java版。

 

       试题六

       阅读以下说明和 C++代码,将应填入 (n) 处的字句写在答题纸的对应栏内。

       【说明】

       传输门是传输系统中的重要装置。传输门具有 Open(打开)、Closed(关闭)、Opening(正在打开)、StayOpen(保持打开)、Closing(正在关闭)五种状态。触发传输门状态转 换的事件有 click、complete 和 timeout 三种。事件与其相应的状态转换如图6-1 所示。

设计模式与软考试题之状态模式(一)_第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所示。

  设计模式与软考试题之状态模式(一)_第2张图片

图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来获取。在本试题中,状态的切换由具体状态类来完成,由环境类来维护各个具体状态类的实例。

 

微笑推荐:深入学习状态模式

 

      参考答案:

【试题六】

(1) state == CLOSED || state == CLOSING

(2) state == OPENING || state == STAYOPEN

(3) state == OPEN

(4) state -> click()

(5) state -> timeout()

(6) state -> complete()

(7) door -> setState(door->OPENING)

 

【试题七】

(1) state == CLOSED || state == CLOSING

(2) state == OPENING || state == STAYOPEN

(3) state == OPEN

(4) state.click()

(5) state.timeout()

(6) state.complete()

(7) door.setState(door.OPENING)

 

【作者:刘伟 http://blog.csdn.net/lovelion

你可能感兴趣的:(设计模式,软考)