尊龙集团官方最新网站尊龙集团官方最新网站

尊龙d88最新首页
尊龙集团官方最新APP

State模式(状态设计模式)

State???

State模式中,我们用类来表示状态。以类来表示状态后,我们就能通过切换类来方便地改变对象的状态。当需要增加新的状态时,如何修改代码这个问题也会很明确。

直接用状态代替硬编码依赖于状态的处理,来执行具体的操作

理清职责

实现功能:

·有一个金库·金库与警报中心相连·金库里有警铃和正常通话用的电话·金库里有时钟,监视着现在的时间·白天的时间范围是9:00~16:59,晚上的时间范围是17:00~23:59和0:00~8:59·金库只能在白天使用·白天使用金库的话,会在警报中心留下记录·晚上使用金库的话,会向警报中心发送紧急事态通知·任何时候都可以使用警铃·使用警铃的话,会向警报中心发送紧急事态通知·任何时候都可以使用电话(但晚上只有留言电话)·白天使用电话的话,会呼叫警报中心·晚上用电话的话,会呼叫警报中心的留言电话

名字=======》》》》》说明State ||表示金库状态的接口DayState ||表示“白天”状态的类。它实现了State接口NightState ||表示“晚上”状态的类。它实现了State接口Context ||表示管理金库状态,并与警报中心联系的接口SafeFrame ||实现了Context接口。在它内部持有按钮和画面显示等UI信息Main || 测试程序行为的类

使用与不使用状态模式对比
    不使用

使用金库时被调用的方法(){if(白天){向警报中心报告使用记录]elseif(晚上){向警报中心报告紧急事态警铃响起时被调用的方法(){向警报中心报告紧急事态正常通话时被调用的方法(){if(白天){呼叫警报中心}elseif(晚上){呼叫警报中心的留言电话}

    使用

表示百天的状态的类{使用金库时被调用的方法(){向警报中心报告使用记录警铃响起时被调用的方法(){向警报中心报告紧急事态正常通话时被调用的方法(){呼叫警报中心表示晚上的状态的类{使用金库时被调用的方法(){向警报中心报告紧急事态警铃响起时被调用的方法(){向警报中心报告紧急事态正常通话时被调用的方法(){呼叫警报中心的留言电话- 相关设计模式◆Singleton模式(第5章)Singleton 模式常常会出现在ConcreteState角色中。在示例程序中,我们就使用了Singleton模式。这是因为在表示状态的类中并没有定义任何实例字段(即表示实例的状态的字段)。◆Flyweight模式(第20章)在表示状态的类中并没有定义任何实例字段。因此,有时我们可以使用Flyweight模式在多个Context 角色之间共享ConcreteState角色。

UML

时序图:

Code

DayState NightState State

public interface State { //设置时间 void doclock(Context context, int hour); // 使用金库 void doUse(Context context); // 按下警铃 void doAlarm(Context context); // 正常通话 void dophone(Context context);}public class NightState implements State { private NightState() { } private static NightState singleton = new NightState(); public static State getInstance() { return (State) singleton; } @Override public void doclock(Context context, int hour) { if (hour >= 9 && hour < 17) { context.changeState(DayState.getInstance()); } } @Override public void doUse(Context context) { context.recordLog("使用金库[晚上]"); } @Override public void doAlarm(Context context) { context.callSecurityCenter("按下警铃[晚上]"); } @Override public void dophone(Context context) { context.recordLog("正常通话[晚上]"); } @Override public String toString() { return "DayState{晚上}"; }}public class DayState implements State { /** * 这里使用单例模式,因为每次改变一次状态都会生成一次实例,非常浪费内存与时间 */ private DayState() { } private static DayState singleton = new DayState(); public static State getInstance() { return singleton; } @Override public void doclock(Context context, int hour) { if (hour < 9 || hour >= 17) { context.changeState(NightState.getInstance()); } } @Override public void doUse(Context context) { context.recordLog("使用金库[白天]"); } @Override public void doAlarm(Context context) { context.callSecurityCenter("按下警铃[白天]"); } @Override public void dophone(Context context) { context.recordLog("正常通话[白天]"); } @Override public String toString() { return "DayState{白天}"; }}Context 、SateFrame 、MainT

···

public class MainT {

public static void main(String[] args) { SateFrame frame = new SateFrame("Safe Smaple"); // 24个小时制 while (true){ for (int i = 0; i < 24; i++) { frame.setClock(i); try { Thread.sleep(1000); }catch (InterruptedException e){ e.printStackTrace(); } } }}

}

public interface Context {//设置时间void setClock(int hour);

// 改变状态void changeState(State state);// 联系警报中心void callSecurityCenter(String msg);// 在警报中心留下记录void recordLog(String msg);

}

public class SateFrame extends Frame implements ActionListener,Context {

// 显示时间private TextField textClock=new TextField(60);// 显示警报中心的记录private TextArea textScreen=new TextArea(10,60);private Button buttonUse=new Button("使用金库");private Button buttonALarm=new Button("按下警铃");private Button buttonPhone=new Button("正常通话");private Button buttonExit=new Button("退出");// 初始状态为白天private State state=DayState.getInstance();public SateFrame(String title) throws HeadlessException { super(title); setBackground(Color.lightGray); setLayout(new BorderLayout()); add(textClock,BorderLayout.NORTH); textClock.setEditable(false); add(textScreen,BorderLayout.CENTER); textScreen.setEditable(false); Panel panel = new Panel(); panel.add(buttonUse); panel.add(buttonALarm); panel.add(buttonPhone); panel.add(buttonExit); add(panel,BorderLayout.SOUTH); pack(); show(); buttonUse.addActionListener(this); buttonALarm.addActionListener(this); buttonPhone.addActionListener(this); buttonExit.addActionListener(this);}/** * 可以看出这里的操作就简化很多了: * 基本只有业务逻辑代码: * 判断状态相关的代码可以直接由相关的状态代码实现, * 即为由类的状态代替了if else代码 */@Overridepublic void actionPerformed(ActionEvent e) { if(e.getSource()==buttonUse){ state.doUse(this); }else if(e.getSource()==buttonALarm){ state.doAlarm(this); }else if(e.getSource()==buttonPhone){ state.dophone(this); }else if(e.getSource()==buttonExit){ System.exit(0); }else{ System.out.println("?"); }}@Overridepublic void setClock(int hour) { String clockstring="现在时间是:"; if(hour<10){ clockstring+="0"+hour+":00"; }else{ clockstring+=hour+":00"; } System.out.println(clockstring); textClock.setText(clockstring); state.doclock(this,hour);}@Overridepublic void changeState(State state) { System.out.println("从"+this.state+"状态变为了"+state+"状态。"); this.state=state;}@Overridepublic void callSecurityCenter(String msg) { textScreen.append("调用---"+msg+"");}@Overridepublic void recordLog(String msg) { textScreen.append("记录---"+msg+"");}

}

···

, 1, 0, 9);

欢迎阅读本文章: 韩建良

尊龙体育官方指定APP

尊龙d88最新首页