1. State模式
类对应的东西可能存在于真实世界中,也可能不存在于真实世界中。State模式就是用类来表示状态。
1.1 State模式的类图
登场角色
-
State(状态)
定义了状态接口,定义了根据不同状态进行不同处理的接口(API),该接口是那些处理内容依赖于状态的方法的集合。 -
ConcreteState(具体状态)
实现了State角色 -
Context(上下文)
Context是持有表示当前状态对象的角色
1.2 示例程序
类一览表
名字 | 说明 |
---|---|
State | 表示金库状态的接口 |
DayState | 表示“白天”状态的类 |
NightState | 表示“晚上”状态的类 |
Context | 表示管理金库的接口 |
SafeFrame | 实现了Context类 |
Main | 测试类 |
uml类图(只含实现关系)
uml类图(看一下依赖关系和聚合关系)
State接口
package xin.ajay.state;
public interface State {
void doClock(Context context,int hour);//设置时间
void doUse(Context context); //使用金库
void doAlarm(Context context); //按下警铃
void doPhone(Context context);//正常通话
}
Context接口
package xin.ajay.state;
/*
一个金库
金库与报警中心相连
金库里有警铃和正常通话用的电话
金库里有时钟,监视着现在的时间
白天(9:00 ~ 16:59),晚上(17:00 ~ 23:59和 0:00 ~ 8:59)
金库只能在白天使用
白天使用,会在警报中心留下记录
晚上使用,会向警报中心发送紧急事态通知
任何时候都可以使用警铃
使用警铃,会向警报中心发送紧急事态通知
任何时候都应该使用电话
白天使用电话,会呼叫警报中心
晚上使用电话,会进行留言
*/
public interface Context {
void setClock(int hour);//设置时间
void changeState(State state);//改变状态
void callSecurityCenter(String mag);//联系报警中心
void recordLog(String msg);//在报警中心留下记录
}
DayState类
package xin.ajay.state.impl;
import xin.ajay.state.Context;
import xin.ajay.state.State;
public class DayState implements State {
private static DayState singleton = new DayState();
private DayState(){};
public static DayState getSingleton() {
return singleton;
}
@Override
public void doClock(Context context, int hour) {
if(hour < 9 || 17 <= hour){
context.changeState(NightState.getSingleton());
}
}
@Override
public void doUse(Context context) {
context.recordLog("使用金库(白天)");
}
@Override
public void doAlarm(Context context) {
context.callSecurityCenter("按下警铃(白天)");
}
@Override
public void doPhone(Context context) {
context.callSecurityCenter("正常通话(白天)");
}
@Override
public String toString() {
return "[白天]";
}
}
NightState类
package xin.ajay.state.impl;
import xin.ajay.state.Context;
import xin.ajay.state.State;
public class NightState implements State {
private static NightState singleton = new NightState();
private NightState(){};
public static NightState getSingleton() {
return singleton;
}
@Override
public void doClock(Context context, int hour) {
if(hour >= 9 && hour <17){
context.changeState(DayState.getSingleton());
}
}
@Override
public void doUse(Context context) {
context.callSecurityCenter("紧急:晚上使用金库!");
}
@Override
public void doAlarm(Context context) {
context.callSecurityCenter("按下警铃(晚上)");
}
@Override
public void doPhone(Context context) {
context.recordLog("晚上的通话录音");
}
@Override
public String toString() {
return "[晚上]";
}
}
SafeFrame类
package xin.ajay.state.impl;
import xin.ajay.state.Context;
import xin.ajay.state.State;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class SafeFrame extends JFrame implements ActionListener, Context {
private JTextField clock = new JTextField(60);
private JTextArea logScreen = new JTextArea(10,60);
private JButton buttonUse = new JButton("使用金库");
private JButton buttonAlarm = new JButton("按下警铃");
private JButton buttonPhone = new JButton("正常通话");
private JButton buttonExit = new JButton("结束");
private State state = DayState.getSingleton();
public SafeFrame(String title) throws HeadlessException {
super(title);
setBackground(Color.LIGHT_GRAY);
setLayout(new BorderLayout());
add(clock,BorderLayout.NORTH);
clock.setEditable(false);
add(logScreen,BorderLayout.CENTER);
logScreen.setEditable(false);
JPanel jPanel = new JPanel();
jPanel.add(buttonUse);
jPanel.add(buttonAlarm);
jPanel.add(buttonPhone);
jPanel.add(buttonExit);
add(jPanel,BorderLayout.SOUTH);
pack();
setVisible(true);
buttonUse.addActionListener(this);
buttonAlarm.addActionListener(this);
buttonPhone.addActionListener(this);
buttonExit.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.toString());
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("错误");
}
}
@Override
public void setClock(int hour) {
String clockString = "现在的时间是";
if(hour<10){
clockString += "0"+hour +":00";
}else {
clockString += hour + ":00";
}
System.out.println(clockString);
clock.setText(clockString);
state.doClock(this,hour);
}
@Override
public void changeState(State state) {
System.out.println("从"+ this.state + "状态变为了"+state+"状态。");
this.state = state;
}
@Override
public void callSecurityCenter(String msg) {
logScreen.append("call! " + msg +"\n");
}
@Override
public void recordLog(String msg) {
logScreen.append("record ... " + msg + "\n");
}
}
Main类
package xin.ajay.state.impl;
public class Main {
public static void main(String[] args) {
SafeFrame f = new SafeFrame("State Simple");
while (true){
for (int i = 0; i < 24; i++) {
f.setClock(i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
结果
鸣谢
GoF《设计模式》和结城浩的《图解设计模式》