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 代码
- */
- @Override
- public 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("?");
- }
- }
- @Override
- public 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);
- }
- @Override
- public void changeState(State state) {
- System.out.println("从"+this.state+"状态变为了"+state+"状态.");
- this.state=state;
- }
- @Override
- public void callSecurityCenter(String msg) {
- textScreen.append("调用 ---"+msg+"\n");
- }
- @Override
- public void recordLog(String msg) {
- textScreen.append("记录 ---"+msg+"\n");
- }
- }
- ...
来源: https://www.cnblogs.com/dgwblog/p/9880151.html