状态模式
状态模式(State Pattern) 又称为状态对象模式。该模式允许一个对象在其内部状态改变时改变其行为。
1状态模式的定义
状态模式的英文原文是:
Allow an Object to alter its behavior when its internal state changes.The object will appear to change its class.
意思是:当一个对象内在状态改变时允许改变行为,这个对象看起来像改变了其类型。
状态模式的核心是封装,状态的变更引起行为的变动,从外部看来就好像该对象对应的类发生改变一样。
状态模式设计的3种角色:
- 抽象状态(State)角色:该角色用以封装环境对象的一个特定状态所对应的行为。
- 具体状态(Concrete State)角色:该角色实现环境的一个状态所对应的行为。
- 环境(Context )角色: 该角色定义客户端需要的接口,并负责具体状态的切换。它会保留一个具体状态类的实例,该实例给出环境对象的现有状态。
状态模式的类图
创建抽象状态
State.java
package com.eric.行为型模式_Part2.状态模式.引例;
/**
* @author Eric
* @ProjectName my_design_23
* @description 抽象状态
* @CreateTime 2020-12-14 16:12:55
*/
public abstract class State {
//定义一个环境角色
protected Context context;
//设置环境
public void setContext(Context context){
this.context = context;
}
//抽象行为
public abstract void handle();
}
创建状态实现类
ConcreteState1.java
package com.eric.行为型模式_Part2.状态模式.引例;
/**
* @author Eric
* @ProjectName my_design_23
* @description 具体状态1
* @CreateTime 2020-12-14 16:18:57
*/
public class ConcreteState1 extends State{
//状态1的行为逻辑处理
@Override
public void handle() {
System.out.println("行为1的逻辑处理。");
}
}
ConcreteState2.java
package com.eric.行为型模式_Part2.状态模式.引例;
/**
* @author Eric
* @ProjectName my_design_23
* @description 具体状态1
* @CreateTime 2020-12-14 16:18:57
*/
public class ConcreteState2 extends State{
//状态2的行为逻辑处理
@Override
public void handle() {
System.out.println("行为2的逻辑处理。");
}
}
创建环境角色
Context.java
package com.eric.行为型模式_Part2.状态模式.引例;
/**
* @author Eric
* @ProjectName my_design_23
* @description 环境角色
* @CreateTime 2020-12-14 16:14:54
*/
public class Context {
//定义状态
public static State state1 = new ConcreteState1();
public static State state2 = new ConcreteState2();
//当前状态
private State currentState;
//获取当前状态
public State getCurrentState()
{
return currentState;
}
//设置状态
public void setCurrentState(State currentState)
{
this.currentState = currentState;
//设置状态中的环境
currentState.setContext(this);
}
//行为委托
public void handle1()
{
//切换到状态1
this.setCurrentState(state1);
this.currentState.handle();
}
public void handle2()
{
//切换到状态2
this.setCurrentState(state2);
this.currentState.handle();
}
}
创建测试类
Client.java
package com.eric.行为型模式_Part2.状态模式.引例;
/**
* @author Eric
* @ProjectName my_design_23
* @description 环境角色
* @CreateTime 2020-12-14 16:14:54
*/
public class Context {
//定义状态
public static State state1 = new ConcreteState1();
public static State state2 = new ConcreteState2();
//当前状态
private State currentState;
//获取当前状态
public State getCurrentState()
{
return currentState;
}
//设置状态
public void setCurrentState(State currentState)
{
this.currentState = currentState;
//设置状态中的环境
currentState.setContext(this);
}
//行为委托
public void handle1()
{
//切换到状态1
this.setCurrentState(state1);
this.currentState.handle();
}
public void handle2()
{
//切换到状态2
this.setCurrentState(state2);
this.currentState.handle();
}
}
测试结果
2状态模式的应用
a.状态模式的优缺点
优点
- 结构清晰
- 遵循设计原则
- 封装性非常好
缺点
- 子类太多,不易管理。
b.状态模式的效果
- 状态模式需要对每一个系统可能取得的状态创建一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。所有与一个特定的状态有关的行为都被包装到一个特定的对象里面,使得行为的定义局域化。因为同样的原因,如果有新的状态以及它对应的行为需要定义时,可以很方便地通过设立新的子类的方式加到系统中,不需要改变其他的类。
- 由于每一个状态都被包装到了类里面,就可以不必采用过程性处理方案,使用长篇累牍的条件转移语句。
- 使用状态模式使系统状态的变化变得很明显。由于不用一些属性来指明系统所所处的状态,因此,就不用担心修改这些属性不当而造成的错误。
- 可以在系统的不同部分使用相同的一些状态类的对象。这种共享对象的方法是与享元模式相符合的,事实上,此时这些状态对象基本上是只有行为而没有内部状态的享元。
- 状态模式会造成大量的小状态类,但是可以使程序免于大量的条件转移语句,使程序实际上更易维护。
- 系统所选的状态子类均是从一个抽象状态类或接口继承而来,Java语言的特性使得在Java语言中使用状态模式较为安全,多态性原则是状态模式的核心。
c.状态模式的使用场景
- 对象的行为依赖于它所处的状态,即行为随状态改变而改变场景。
- 对象在某个方法里依赖于一重或多重条件分支语句,此时可以使用状态模式将分支语句中的每一个分支都包装到一个单独的类中,使得这些条件分支语句能够以类的方式独立存在并独立演化。这样,就不会在影响到其他部分。
3状态模式的实例
使用状态模式模拟电视频道的转换。
模拟电视机的类图
创建抽象频道接口
Channel.java
package com.eric.行为型模式_Part2.状态模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 频道接口
* @CreateTime 2020-12-15 10:08:12
*/
//频道(抽象状态)
public interface Channel {
//播放频道中的节目
public void display();
}
创建Channel的实现类
CCTV1.java
package com.eric.行为型模式_Part2.状态模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 中央电视台第一频道
* @CreateTime 2020-12-15 10:12:13
*/
public class CCTV1 implements Channel {
@Override
public void display() {
System.out.println("CCTV1 新闻联播");
}
}
CCTV2.java
package com.eric.行为型模式_Part2.状态模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 中央电视台第一频道
* @CreateTime 2020-12-15 10:12:13
*/
public class CCTV2 implements Channel {
@Override
public void display() {
System.out.println("CCTV2 经济半小时");
}
}
CCTV3.java
package com.eric.行为型模式_Part2.状态模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 中央电视台第一频道
* @CreateTime 2020-12-15 10:12:13
*/
public class CCTV3 implements Channel {
@Override
public void display() {
System.out.println("CCTV3 非常6+1");
}
}
CCTV14.java
package com.eric.行为型模式_Part2.状态模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 中央电视台第一频道
* @CreateTime 2020-12-15 10:12:13
*/
public class CCTV14 implements Channel {
@Override
public void display() {
System.out.println("CCTV14 开心超人");
}
}
创建TV类
TV.java
package com.eric.行为型模式_Part2.状态模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 电视
* @CreateTime 2020-12-15 10:10:15
*/
//电视
public class TV {
//电视可以看的频道
public final static Channel CCTV1 = new CCTV1();
public final static Channel CCTV2 = new CCTV2();
public final static Channel CCTV3 = new CCTV3();
public final static Channel CCTV14 = new CCTV14();
//当前频道
private Channel channel;
//设置频道
public void setChannel(Channel channel)
{
this.channel = channel;
}
//播放CCTV1
public void disCCTV1()
{
this.setChannel(CCTV1);
this.channel.display();
}
//播放CCTV2
public void disCCTV2()
{
this.setChannel(CCTV2);
this.channel.display();
}
//播放CCTV3
public void disCCTV3()
{
this.setChannel(CCTV3);
this.channel.display();
}
//播放CCTV14
public void disCCTV14()
{
this.setChannel(CCTV14);
this.channel.display();
}
}
创建测试类
package com.eric.行为型模式_Part2.状态模式.例1;
/**
* @author Eric
* @ProjectName my_design_23
* @description 测试类
* @CreateTime 2020-12-15 10:19:31
*/
public class Test {
public static void main(String[] args) {
TV tv = new TV();
//换台
tv.disCCTV1();
tv.disCCTV2();
tv.disCCTV3();
tv.disCCTV14();
}
}
测试结果