状态模式
当一个对象内在状态改变时允许改变行为,这个对象看起来改变了其类型。
状态模式的核心是封装,状态的变更引起行为的变动,从外部看来就好像该对象对应的类发生改变一样。
状态模式角色
- 抽象状态(State)角色:该角色用于封装环境对象的一个特定状态所对应的行为;
- 具体状态(Concrete State)角色:该角色实现环境对象一个特定状态所对应的行为;
- 环境(Context)角色:该角色定义客户端需要的接口,并负责具体状态的切换。它会保留一个具体状态类的实例,该实例给出环境对象的现有状态。
状态模式的优点
- 结构清晰;
- 遵循设计原则;
- 封装性非常好。
状态模式的缺点
子类太多,不易扩展
状态模式效果
- 状态模式需要对每一个系统可能取得的状态创建一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。所有与一个特定的状态有关的行为都被封装到一个特定的对象里面,使得行为定义局域化。因为同样的原因,如果有新的状态以及它的行为需要定义时,可以方便地通过设立新的子类的方式加到系统里,不需要改动其他的类;
- 由于每一个状态都被封装到了类里面,就可以不必采用过程性的处理方式,使用长篇累牍的条件转移语句;
- 使用状态模式使系统状态的变化变得很明显。由于不用一些属性来指明系统所处的状态,因此,就不用当心这些属性不适当而造成错误;
- 可以在系统的不同部分使用相同的一些状态类的对象。这种共享对象的方法是与亨元模式相符合的,事实上,此时这些状态对象基本上是只有行为而没有内部状态的亨元;
- 状态模式会造成大量的小状态类,但是可以使程序免于大量的条件转移语句,使程序更易于维护;
- 系统所选的状态子类均是从一个抽象状态类或接口继承而来,Java语言的特性使得在Java语言使用状态模式较为安全,多态性原则是状态模式的核心。
使用场景
- 对象的行为依赖于它所处的状态,即行为随状态改变而改变的场景;
- 对象在某个方法里依赖于一重或多重条件分支语句,此时可以使用状态模式将分支语句的每一个分支都包装到一个单独的类中,使得这些分支条件语句能够以类的方式独立存在和演化。如此,维护这些独立的类就不再影响到系统的其他部分。
<span style="font-size:18px;">package state;
//频道(抽象状态)
public interface Channel {
//播放频道中的节目
public void display();
}
</span>
<span style="font-size:18px;">package state;
//具体状态,实现抽象状态
public class CCTV1 implements Channel {
public void display() {
System.out.println("CCTV1 新闻联播");
}
}
</span>
<span style="font-size:18px;">package state;
//具体状态,实现抽象状态
public class CCTV2 implements Channel {
public void display() {
System.out.println("CCTV2 经济半小时");
}
}
</span>
<span style="font-size:18px;">package state;
//具体状态,实现抽象状态
public class CCTV3 implements Channel {
public void display() {
System.out.println("CCTV3 非常 6+1");
}
}
</span>
<span style="font-size:18px;">package state;
//环境角色
public class TV{
//播放频道(环境持有的状态)
public final static Channel CCTV1 = new CCTV1();
public final static Channel CCTV2 = new CCTV2();
public final static Channel CCTV3 = new CCTV3();
//当前频道(当前状态)
private Channel currentChannel;
//设定当前状态
public void SetChannel(Channel channel){
this.currentChannel = channel;
}
//播放CCTV1频道的节目
public void disCCTV1() {
// TODO Auto-generated method stub
//先设定当前状态
this.SetChannel(CCTV1);
//设定完状态,引起行为变化
this.currentChannel.display();
}
//播放CCTV2频道的节目
public void disCCTV2() {
// TODO Auto-generated method stub
//先设定当前状态
this.SetChannel(CCTV2);
//设定完状态,引起行为变化
this.currentChannel.display();
}
//播放CCTV3频道的节目
public void disCCTV3() {
// TODO Auto-generated method stub
//先设定当前状态
this.SetChannel(CCTV3);
//设定完状态,引起行为变化
this.currentChannel.display();
}
}
</span>
<span style="font-size:18px;">package state;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//调用环境角色
TV tv = new TV();
//换频道
tv.disCCTV1();
tv.disCCTV2();
tv.disCCTV3();
}
}
</span>