状态模式

来源:互联网 发布:mac使用u盘重装系统 编辑:程序博客网 时间:2024/06/02 18:38

0.前言

生活中,我们每个人都有着不同的状态,并且我们在不同的状态下会做出不同的事情,与此同时,我们的这些状态是在经常改变的。同样,在设计模式中,有一种模式专门为类似“我们人”这种对象提供状态的管理与切换。这种模式就叫做状态模式。


1.状态模式

状态模式允许一个对象在起内部改变时,改变它的行为,对象看起来似乎修改了它的类。


2.实际案例

有一个屏幕放大工具,拥有三种状态,分别为:NormalState,LargerState,LargestState。分别对应的含义是:正常状态,2倍放大状态,4倍放大状态。在正常状态时,点击按钮成为2倍放大状态,再点击按钮成为4倍放大状态,再点击按钮则又回到正常状态。请用状态模式实现。


3.具体分析

在上面的例子中,我们知道,这个屏幕(Screen类)即是上下文类,拥有三种状态,分别对应于:NormalState(正常状态),LargerState(2倍放大状态),LargestState(4倍放大状态),并且这三个状态之间可以进行随时的切换。正常状态------按钮点击-----》2倍放大状态---------按钮点击-------》4倍放大状态-------按钮点击------》正常状态。综上述,所有对应的类如下所示:

Screen :屏幕类

State抽象:状态类

NormalState:正常状态类

LargerState:2倍放大类

LargestState:4倍放大类

Client:客户端类


4.具体实现

package liu.shen;/** * 客户端类 * @author Object * */public class Client {public static void main(String []args){Screen screen = new Screen();//新建一个Screen对象System.out.println("--------------开始第1轮点击------------");screen.getState().display();screen.click();//外表上点击事件,内部状态切换screen.getState().display();//这里的display()可以放到screen类中调用,这样就不必使用.getState()方法了//使用getState()方法肯定是为了获取某一个值。假设我们不想这么获取的话,我们就直接可以在拥有getState()方法的类中调用screen.click();screen.getState().display();screen.click();screen.getState().display();}}

package liu.shen;/** * Screen类相当于Context类,即上下文类 * @author Object * */public class Screen {private State state;//与State关联private String value;//表示附加值private LargerState largerState = new LargerState();public Screen (){this.state = new NormalState();//构造对象时,将state的值赋为NormalState的对象this.value = "Normal";}//屏幕有点击方法public void click(){System.out.print("我被点击了一次!   ");this.changeState();}//设置状态值public void setState(State state) {this.state = state;};public State getState() { return this.state ;};//状态切换类private void changeState(){//如果未Normal状态if(this.value.equals("Normal")){this.value ="Larger";this.setState(new LargerState());}//如果未Larger状态else if(this.value.equals("Larger")){this.value ="Largest";this.setState(new LargestState());}//如果为Largest状态else if(this.value.equals("Largest")){this.value ="Normal";this.setState(new NormalState());}}}

package liu.shen;public abstract class State {public abstract void display();}

package liu.shen;public class LargerState extends State{@Overridepublic void display() {// TODO Auto-generated method stubSystem.out.println("This is LargerState!");}}

package liu.shen;public class LargestState extends State{@Overridepublic void display() {// TODO Auto-generated method stubSystem.out.println("This is LargestState!");}}

package liu.shen;public class NormalState extends State{@Overridepublic void display() {// TODO Auto-generated method stubSystem.out.println("This is NormalState!");}}

5.实现结果



6.上面我们能够 看到,我们是在Screen类中进行状态的转换,即Screen类中的changeState()方法。现在我们使用在具体状态类中实现转换方法。具体代码如下:

package liu.shen;/** * 客户端类 * @author Object * */public class Client {public static void main(String []args){Screen screen = new Screen();//新建一个Screen对象System.out.println("--------------开始第1轮点击------------");screen.getState().display();screen.click();//外表上点击事件,内部状态切换screen.getState().display();//这里的display()可以放到screen类中调用,这样就不必使用.getState()方法了//使用getState()方法肯定是为了获取某一个值。假设我们不想这么获取的话,我们就直接可以在拥有getState()方法的类中调用screen.click();screen.getState().display();screen.click();screen.getState().display();}}

package liu.shen;/** * Screen类相当于Context类,即上下文类 * @author Object * */public class Screen {public  static State state;//与State关联private String value;//表示附加值private LargerState largerState = new LargerState();public Screen (){this.state = new NormalState();//构造对象时,将state的值赋为NormalState的对象this.value = "Normal";}//屏幕有点击方法public void click(){System.out.print("我被点击了一次!   ");state.changeState(this);}//设置状态值public  void setState(State state) {this.state = state;};public State getState() { return this.state ;};/*//状态切换类private void changeState(){//如果未Normal状态if(this.value.equals("Normal")){this.value ="Larger";this.setState(new LargerState());}//如果未Larger状态else if(this.value.equals("Larger")){this.value ="Largest";this.setState(new LargestState());}//如果为Largest状态else if(this.value.equals("Largest")){this.value ="Normal";this.setState(new NormalState());}}*/}

package liu.shen;public abstract class State {protected String value;//如果为private,则子类不能进行访问public abstract void display();//在具体状态类中实现状态转换public abstract void changeState(Screen screen);//这里的Screen需要知道是哪一个Screen//如果在子类中新建一个Screen类,则和Screen类中生成的screen类不同 }

package liu.shen;public class NormalState extends State{public NormalState(){this.value = "Normal";}@Overridepublic void display() {// TODO Auto-generated method stubSystem.out.println("This is NormalState!");}//实现状态转换,得知道当前是什么状态----》使用一个值@Overridepublic void changeState(Screen screen) {// TODO Auto-generated method stubif(value.equals("Normal")){screen.setState(new LargerState());}}}

package liu.shen;public class LargerState extends State{public LargerState(){this.value = "Larger";}@Overridepublic void display() {// TODO Auto-generated method stubSystem.out.println("This is LargerState!");}@Overridepublic void changeState(Screen screen) {// TODO Auto-generated method stubif(value.equals("Larger")){screen.setState(new LargestState());}}}

package liu.shen;public class LargestState extends State{public LargestState(){this.value = "Largest";}@Overridepublic void display() {// TODO Auto-generated method stubSystem.out.println("This is LargestState!");}@Overridepublic void changeState(Screen screen) {// TODO Auto-generated method stubif(value.equals("Largest")){screen.setState(new NormalState());}}}

7.实现结果



8.模式总结

状态模式中最为重要的是要记住这么三点:(1)一个对象拥有很多种状态。(2)不同的状态之间经常切换。(3)不同的状态有着不同的行为。

由(1),我们则需要将这些不同的状态抽象出来,形成一个抽象类,比如说上面的State类。然后将状态之间共同的方法放到抽象类中。

由(2),我们需要实现一个状态转换的方法,这个方法可以在环境类(或者说是上下文类即Context类)中实现,比如说本文中Screen类的changeState()方法,也可以是具体状态类中的方法来负责转换。

由(3)知,我们在上面针对不同的行为是使用System.out.println()方法来满足,但是现实需求中,涉及到接口污染等问题,的确显得有点麻烦。

(4)另外一个比较重要的地方就是,在使用具体状态类中实现状态转换的时候,转换的状态(state)是属于哪一个(Screen)的状态,在我们上面的这个例子中,就是通过注入的方式,将当前需要改变转换状态的对象传给状态转换函数。对应文中的代码是

public void changeState(Screen screen) {// TODO Auto-generated method stubif(value.equals("Largest")){screen.setState(new NormalState());}}

//屏幕有点击方法public void click(){System.out.print("我被点击了一次!   ");state.changeState(this);//注意这里的this}




1 0
原创粉丝点击