文档章节

设计模式-状态模式

fengsehng
 fengsehng
发布于 2016/11/09 09:12
字数 2170
阅读 9
收藏 0

模式动机

在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。

在UML中可以使用状态图来描述对象状态的变化。

模式定义

状态模式(State Pattern) :允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。

状态模式所涉及到的角色

  ●  环境(Context)角色,也成上下文:定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。

  ●  抽象状态(State)角色:定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。

  ●  具体状态(ConcreteState)角色:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

uml

这里写图片描述

具体例子:

策略模式和状态模式是双胞胎,在出生时才分开。你已经知道,策略模式是围绕可以互换的算法来创建成功业务的,然而,状态走的是更崇高的路,它通过改变对象内部的状态来帮助对象控制自己的行为。

题例:

万能糖果公司 我们认为糖果机的控制器需要如下图般的工作,希望你能用Java语言帮我们实现它,而且需要让设计能够尽量有弹性而且好维护,因为将来我们可能要为它增加更多的行为。
这里写图片描述

没错上图是一个状态图。

1:首先找出所有的状态:“没有25分钱”,“有25分钱”,“糖果售罄”,“售出糖果”。

2:接下来,创建一个实例变量来持有目前的状态,然后定义每个状态的值: final static int SOLD_OUT=0; final static int NO_QUARTER=1; final static int HAS_QUARTER=2; final static int SOLD=3; int state =SOLD_OUT;

final static int SOLD_OUT=0; 
final static int NO_QUARTER=1; 
final static int HAS_QUARTER=2; 
final static int SOLD=3; 
int state =SOLD_OUT;

3:现在,我们将所有系统中可以发生的动作整合起来: “投入25分钱”,“退回25分钱”,“转动曲柄”,“发放糖果” 这些动作是糖果机的接口,这是你能对糖果机做的事情, 调用任何一个动作都会造成状态的转换, 发放糖果更多是糖果机的内部动作,机器自己调用自己。

4:现在,我们创建了一个类,它的作用就像是一个状态机,第每一个动作,我们都创建了一个对应的方法,这些方法利用条件语句来决定在每个状态内什么行为是恰当的。比如对“投入25分钱”这个动作来说,我们可以把对应方法写成下面的样子:
这里写图片描述

新的设计

不要维护我们现有的代码,我们重写它以便于将状态对象封装在各自的类中,然后在动作发生时委托给当前状态。
1:首先,我们定义一个State接口,在这个接口内,糖果机的每个动作都有一个对应的方法。

2:然后为机器中的每个状态实现状态类,这些类将负责在对应的状态下进行机器的行为。

3:最后,我们要摆脱旧的条件代码,取而代之的方法是,将动作委托到状态类。 现在我们要把一个状态的所有行为放在一个类中,这么一来我们将行为局部化了,并使得事情更容易改变和理解。

定义状态接口和类 我们先完成第一个版本的糖果机的重新实现之后,再回来处理添加“赢家”的修改。 首先让我们创建一个State接口,所有的状态都必须实现这个接口:

interface State { void insertQuarter(); 
void ejectQuarter();
 void turnCrank(); 
 void dispense(); }

这里写图片描述

重新改造糖果机

class GumballMachine_ 
{ State soldOutState; 
State noQuarterState; 
State hasQuarterState; 
State soldState; 
State state = soldState;
 int count = 0; 
 public GumballMachine_(int count) 
 { soldOutState = new SoldOutState(this); noQuarterState = new NoQuarterState(this); hasQuarterState = new HasQuarterState(this); soldOutState = new SoldState(this); 
 this.count = count; 
 if (count > 0) 
 { state = noQuarterState; } } 
 public void insertQuarter()
  { state.insertQuarter(); } 
  public void ejectQuarter() 
  { state.ejectQuarter(); } 
  public void turnCrank(){ state.turnCrank(); state.dispense(); }
   void setState(State state){ this.state=state; }
    void releaseBall(){ System.out.println(); if(count!=0){ count=count-1; } }
     public State getSoldState() { return soldState; } public State getHasQuarterState() { return hasQuarterState; } 
     public State getNoQuarterState() { return noQuarterState; } 
     public State getSoldOutState() { return soldOutState; } } 

状态类举例

class HasQuarterState implements State { GumballMachine_ gumballMachine; 
public HasQuarterState(GumballMachine_ gumballMachine) { this.gumballMachine = gumballMachine; }
 @Override public void insertQuarter() { System.out.println("这是一个对此状态不恰当的动作"); } @Override public void ejectQuarter() { System.out.println("退出顾客的25分钱,并将状态转换到NoQuarterState状态"); gumballMachine.setState(gumballMachine.getNoQuarterState()); }
@Override public void turnCrank() { System.out.println("当曲柄转动,我们将状态转换到SoldState"); gumballMachine.setState(gumballMachine.getSoldState()); }
@Override public void dispense() { System.out.println("这是次状态的另一个不恰当动作"); } } 

策略模式和状态模式的区别

但是这两个模式的差别在于它们的“意图” 以状态模式而言

我们将一群行为封装在状态对象中,context的行为随时可委托到那些状态对象中的一个,随着时间而流逝,当前状态在状态对象集合中游走改变,以反映出context内部的状态,因此,context的行为也会跟着改变,但是context的客户对于状态对象了解不多,甚至根本是浑然不觉。

而策略模式而言,客户通常主动指定Context所要组合的策略对象时哪一个。现在,固然策略模式让我们具有弹性,能够在运行时改变策略,但对于某个context对象来说,通常都只有一个最适当的策略对象。 一般的,我们把策略模式想成是除了继承之外的一种弹性替代方案,如果你使用继承定义了一个类的行为,你将被这个行为困住,是指要修改它都很难,有了策略模式,你可以通过组合不同的对象来改变行为。

我们把状态模式想成是不用咋icontext中防止旭东条件判断的替代方案,通过将行为包装进状态对象中,你可以通过在context内简单地改变状态对象来改变context的行为。

优点:

封装了转换规则。
枚举可能的状态,在枚举状态之前需要确定状态种类。
将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

缺点:

状态模式的使用必然会增加系统类和对象的个数。
状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

适用环境

对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为。

代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,使客户类与类库之间的耦合增强。在这些条件语句中包含了对象的行为,而且这些条件对应于对象的各种状态。

我的微信二维码如下,欢迎交流讨论

这里写图片描述

欢迎关注《IT面试题汇总》微信订阅号。每天推送经典面试题和面试心得技巧,都是干货!

微信订阅号二维码如下:

这里写图片描述

© 著作权归作者所有

共有 人打赏支持
fengsehng
粉丝 4
博文 284
码字总数 214494
作品 0
朝阳
程序员
私信 提问
设计模式 2014-12-19

book: 阎宏《JAVA与模式》 架构设计栏目 http://blog.csdn.net/enterprise/column.html 概要: http://bbs.csdn.net/forums/Embeddeddriver 23种设计模式分别是: 1.单例模式 2.工厂方法模式...

jayronwang
2014/12/19
0
0
《PHP设计模式大全》系列分享专栏

《PHP设计模式大全》已整理成PDF文档,点击可直接下载至本地查阅 https://www.webfalse.com/read/201739.html 文章 php设计模式介绍之编程惯用法第1/3页 php设计模式介绍之值对象模式第1/5页...

kaixin_code
2018/11/06
0
0
【设计模式笔记】(十六)- 代理模式

一、简述 代理模式(Proxy Pattern),为其他对象提供一个代理,并由代理对象控制原有对象的引用;也称为委托模式。 其实代理模式无论是在日常开发还是设计模式中,基本随处可见,中介者模式中...

MrTrying
2018/06/24
0
0
Ubuntu中vi卸载与安装/使用模式

Ubuntu中安装的vi是vim-common版本,与centos系统中vi使用方式不同,编辑使用不惯, 遂卸载重装,卸载命令:sudo apt-get remove vim-common 卸载完毕后重新安装;输入命令:sudo apt-get in...

唐十三郎
2018/11/27
0
0
JavaScript 中常见设计模式整理

开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式。本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知。 JavaScript 中...

牧云云
2018/05/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

test

//// main.c// Test//// Created by 吕颖 on 2019/1/16.// Copyright © 2019年 carmen. All rights reserved.//#include <stdio.h>#include <stdlib.h>#include <t......

carmen-ly
今天
1
0
Android webview热门组件agentweb:4.0.2无法自适应的问题

Android webview热门组件agentweb:4.0.2无法自适应的问题 //设置自适应屏幕,两者合用mAgentWeb.getAgentWebSettings().getWebSettings().setUseWideViewPort(true); //将图片调整到适合w...

Gemini-Lin
今天
5
0
如何维护一个自己的 golang doc 服务

本文内容是如何维护一个golang 在线的doc 服务。 1 什么是godoc ? godoc 是 golang 官方提供的文档生成工具, 2 为什么要有godoc ? 我们经常遇到一个问题,就是代码和文档不一致,线上代码版...

鼎铭
今天
5
0
js中的对象创建的模式以及继承模式

对象创建模式: 工厂模式 构造函数模式 原型模式 继承模式 原型式继承 寄生式继承 构造函数 原型式和构造函数的组合式(缺点:运行两次超类类函数,积累函数的属性被挂载在原型对象上和实例对...

莫西摩西
昨天
3
0
大数据教程(11.5)仓库工具hive的实现机制

上一篇文章介绍了hadoop联邦集群的搭建过程。至此,hadoop的整个知识系统就差不多结束了。本篇博客开始,博主将分享数据仓库hive工具的原理以及使用。 一、Hive基本概念 (1)什么是Hive Hive...

em_aaron
昨天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部