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

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

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

参考答案:

【试题六】

(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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值