目录
状态模式
允许一个对象在其内部状态改变时,改变他的行为。
类型:行为型
使用场景:一个对象存在多个状态(不同状态下行为不同),且状态可以互相转换时。例如电梯在上升或下降的时候不能开门,只有在电梯停在某一层的时候才可以开门。
优点:将不同的状态隔离。把各种状态的转换逻辑分不到State的子类中,减少相互间的依赖。增加新的状态比较简单。
缺点:在状态多的业务场景导致类数目增加,系统变得复杂。
例子:
public abstract class VideoState {
protected VideoStateContext videoStateContext;
public void setVideoStateContext(VideoStateContext videoStateContext) {
this.videoStateContext = videoStateContext;
}
public abstract void play();
public abstract void speed();
public abstract void pause();
public abstract void stop();
}
public class PlayState extends VideoState {
@Override
public void play() {
System.out.println("正常播放视频");
}
@Override
public void speed() {
this.videoStateContext.setVideoState(VideoStateContext.SPEED_STATE);
}
@Override
public void pause() {
this.videoStateContext.setVideoState(VideoStateContext.PAUSE_STATE);
}
@Override
public void stop() {
this.videoStateContext.setVideoState(VideoStateContext.STOP_STATE);
}
}
public class PauseState extends VideoState {
@Override
public void play() {
this.videoStateContext.setVideoState(VideoStateContext.PLAY_STATE);
}
@Override
public void speed() {
this.videoStateContext.setVideoState(VideoStateContext.SPEED_STATE);
}
@Override
public void pause() {
System.out.println("暂停播放视频");
}
@Override
public void stop() {
this.videoStateContext.setVideoState(VideoStateContext.STOP_STATE);
}
}
public class SpeedState extends VideoState {
@Override
public void play() {
this.videoStateContext.setVideoState(VideoStateContext.PLAY_STATE);
}
@Override
public void speed() {
System.out.println("快进视频");
}
@Override
public void pause() {
this.videoStateContext.setVideoState(VideoStateContext.PAUSE_STATE);
}
@Override
public void stop() {
this.videoStateContext.setVideoState(VideoStateContext.STOP_STATE);
}
}
public class StopState extends VideoState {
@Override
public void play() {
this.videoStateContext.setVideoState(VideoStateContext.PLAY_STATE);
}
@Override
public void speed() {
System.out.println("ERROR 停止状态下无法快进");
}
@Override
public void pause() {
System.out.println("ERROR 停止状态下无法暂停");
}
@Override
public void stop() {
System.out.println("停止播放视频");
}
}
public class VideoStateContext {
private VideoState videoState;
public final static PlayState PLAY_STATE = new PlayState();
public final static SpeedState SPEED_STATE = new SpeedState();
public final static PauseState PAUSE_STATE = new PauseState();
public final static StopState STOP_STATE = new StopState();
public VideoState getVideoState(){
return videoState;
}
public void setVideoState(VideoState videoState) {
this.videoState = videoState;
this.videoState.setVideoStateContext(this);
}
public void play() {
this.videoState.play();
}
public void speed() {
this.videoState.speed();
}
public void pause() {
this.videoState.pause();
}
public void stop() {
this.videoState.stop();
}
}
public class Test {
public static void main(String[] args) {
VideoStateContext videoStateContext = new VideoStateContext();
videoStateContext.setVideoState(new PlayState());
System.out.println("当前状态" + videoStateContext.getVideoState().getClass().getSimpleName());
videoStateContext.pause();
System.out.println("当前状态" + videoStateContext.getVideoState().getClass().getSimpleName());
videoStateContext.speed();
System.out.println("当前状态" + videoStateContext.getVideoState().getClass().getSimpleName());
videoStateContext.stop();
System.out.println("当前状态" + videoStateContext.getVideoState().getClass().getSimpleName());
videoStateContext.pause();
System.out.println("当前状态" + videoStateContext.getVideoState().getClass().getSimpleName());
}
}
类图:
贯穿始终的就是上下文,每次的状态改变,也需要更改上下文中的状态。
用到设计模式的源码:
状态模式在框架中的运用比较少,多用于实际业务中。
设计模式之间的联系及区别
单例模式和工厂模式
在一些场景中,可以把一些工厂类设计成单例模式的。
单例模式和享元模式
一些业务场景中有很多单例对象,可以通过享元模式和单例模式的结合来完成单例对象的获取。这种情况下,享元模式的应用就相当于单例模式的工厂,只不过这个工厂的对象是已经创建好的。
外观模式和中介者模式
外观模式关注的是外界和子系统之间的交互,中介者模式关注的是子系统之间的交互。
外观模式和单例模式
通常可以把外观模式中的对象做成单例模式来使用。
外观模式和抽象工厂模式
外观类通过抽象工厂获取子系统的实例,这样子系统可以将内部对外观类独立。
装饰者模式和代理模式
装饰者模式注重在一个对象上动态的添加行为方法。代理模式注重控制对对象的访问,代理模式的代理类可以对客户隐藏对象的具体信息。通常在使用代理模式的时候,会在一个代理类中创建对象的实例,而对于装饰者模式,会把对象作为一个参数传给装饰者的构造器。
装饰者模式和适配器模式
他们都可以叫做包装模式。装饰者和被装饰者可以实现相同的接口,或者装饰者是被装饰者的子类。对于适配器模式,是配的类和被适配的类具有不同的接口。
适配器模式和外观模式
他们都是对现有类、现有系统的封装。外观模式定义了新的借口,适配器模式复用原有的接口。适配器模式使两个已有的接口协同工作,外观模式在现有的系统中提供一个更为方便的访问入口。如果强行把外观模式也叫适配器的话,二者适配粒度不同,外观模式用来适配整个子系统,外观所针对的对象粒度更大。
享元模式和代理模式
代理模式肯定是代理一个类,生成代理类需要花费的资源和时间会很多,那么就可以使用享元模式提高程序的处理速度。
享元模式和单例模式
关于容器单例,就是二者的结合。
组合模式和访问者模式
可以使用访问者模式访问组合模式中的递归结构。
桥接模式和组合模式
组合模式强调部分和整体的组合,而桥接模式强调平行级别上不同类的组合。
桥接模式和适配器模式
二者都是为了让两个系统配合工作。适配器模式会改变已有的接口,让他们之间相互配合。桥接模式是分离抽象和具体的实现,目的就是分离。适配器模式把功能上相似但接口不同的类适配起来,而桥接模式把类和抽象分离开,在此基础上是这些层次结构结合起来。
适配器模式和代理模式
适配器模式主要考虑改变对象的接口,代理模式不能改变所代理类的接口。
模板方法模式和工厂方法模式
工厂方法是模板方法的特殊实现。
模板方法模式和策略模式
他们都有封装算法。策略模式目的是使不同的算法可以相互替换,并且不影响应用层客户端的使用。模板方法模式针对定义一个算法的流程,将一些不太一样的具体实现步骤交给子类实现。模板方法模式不改变算法的流程,策略模式可以改变算法的流程,并且他们之间可以相互替换。
迭代器模式和访问者模式
二者都是迭代的访问集合对象中的元素。访问者模式扩展开放的是在访问时对对象的操作上,迭代器模式扩展开放的是在集合对象的种类上。
策略模式和工厂模式
工厂模式是创建型的,策略模式是行为型的。工厂模式接受指令,创建出符合要求的具体对象。策略模式接受已经创建好的对象,实现不同的行为。
策略模式和状态模式
策略模式在使用时,应用层需要知道使用哪个策略。状态模式在使用时,应用层不需要关心状态,这些状态会自动转换。一个目标有一个行为,对于这个行为有多种实现方式,使用策略模式。一个目标有多个状态,不同状态下行为有差异,且这些状态可以发生转换时,用状态模式。
解释器模式和适配器模式
适配器模式不需要预先知道适配的规则。解释器需要把规则写好,根据这些规则执行解释。
备忘录模式和状态模式
备忘录模式中会用实例表示状态,存档是对象的实例。对于状态模式,是一个类表示一个状态。
命令模式和备忘录模式
二者经常结合使用,可以使用备忘录模式保存命令。
中介者模式和观察者模式
二者可以结合使用。使用观察者模式实现中介者模式中角色间的通讯。
责任链模式和状态模式
责任链模式中每个对象并不知道下一个要处理的对象是谁,只有在应用层来设定链条的顺序。状态模式知道下一个对象是谁,在编译时就设定好。
访问者模式和迭代器模式
二者都是在某种数据结构上进行处理。访问者模式注重在保存在数据结构中的元素进行特定的处理,重点是处理。迭代器模式主要在于遍历保存在数据结构中的元素,重点是遍历。
状态模式和享元模式
二者可以配合使用。状态模式在没有对应的属性时,可以使用享元模式在多个上下文中共享这些对象的实例。