疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java与设计模式状态模式


 

  概念:状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变,也就是不同状态对应不同的行为。状态模式的示意性类图如下所示:

  UML类图:Context:可以理解成控制类

  State是状态接口

  ConcreteStateA和ConcreteStateB可以认为是接口的实现,也就是具体的状态实现类。

  使用场景:对象的状态决定对象的行为,在运行时根据状态动态调整对象的行为。

  代码中有复杂的ifelse判断,且这些分支判断和状态有关系。

  实际场景:(1)电视开关机状态,电视开机状态下才可以进行各种操作,关机状态下,不能进行各项操作。

  (2)WIFI状态,WIFI开状态下可以连接WIFI,关闭状态不可进行操作。

  (3)登录状态,这个在开发中较为常用,一般在进入系统实现分享转发等操作时要先判断用户的登录状态,若已经登录则可进行操作,否则提示用户登录。

  我们来实现场景1.

  首先创建一个状态接口(对应UML类图中的State接口):

  packagecom.state.demo;publicinterfaceTvState{ /** *电视状态的接口,里面提供四种方法 */ voidnextChanel(); voidpreChanel(); voidturnUp(); voidturnDown();}

  接下来两个实现类(对应UML类图中ConcreteStateA):

  packagecom.state.demo;publicclassPowerOnStateimplementsTvState{ /** *开机状态下,遥控器按钮有效 */ @Override publicvoidnextChanel(){ System.out.println("---------下一频道-----------------------"); } @Override publicvoidpreChanel(){ System.out.println("---------上一频道-----------------------"); } @Override publicvoidturnUp(){ System.out.println("---------音量增大-----------------------"); } @Override publicvoidturnDown(){ System.out.println("---------音量减小-----------------------"); }}

  实现类2(对应UML类图中ConcreteStateB):

  packagecom.state.demo;publicclassPowerOffStateimplementsTvState{ /** *关机状态下,所有按钮无效 */ @Override publicvoidnextChanel(){ System.out.println("---------关机状态不可用,请先开机-----------------------"); } @Override publicvoidpreChanel(){ System.out.println("---------关机状态不可用,请先开机-----------------------"); } @Override publicvoidturnUp(){ System.out.println("---------关机状态不可用,请先开机-----------------------"); } @Override publicvoidturnDown(){ System.out.println("---------关机状态不可用,请先开机-----------------------"); }}

  接下来控制类(对应UML类图中Context):

  packagecom.state.demo;publicclassTvController{ TvStatetvState=null; publicvoidsetTvState(TvStatetvState){ this.tvState=tvState; } /** *开机 */ publicvoidturnOnTv(){ setTvState(newPowerOnState()); System.out.println("--------开机啦---------------"); } /** *关机 */ publicvoidturnOffTv(){ setTvState(newPowerOffState()); System.out.println("--------关机啦---------------"); } /** *下一频道 */ publicvoidnextChanel(){ tvState.nextChanel(); } publicvoidpreChanel(){ tvState.preChanel(); } publicvoidturnUp(){ tvState.turnUp(); } publicvoidturnDown(){ tvState.turnDown(); }}

  最后,编写一个测试类,测试以上代码:

  packagecom.state.demo;publicclassTestClass{ publicstaticvoidmain(String[]args){ TvControllertvController=newTvController();//创建一个控制类 tvController.turnOnTv();//首先开机 tvController.nextChanel(); tvController.turnDown(); tvController.turnOffTv();//关机 tvController.turnDown();//关机后功能不再提供 }}

  运行实例如下:

  这里有些逻辑小问题,就是在已经开机的状态下,用户再次调用开机要进行提示,这时我们可以在控制类中加入如下代码;

  packagecom.state.demo;publicclassTvController{ privatebooleanisTvOn=false; TvStatetvState=null; publicvoidsetTvState(TvStatetvState){ this.tvState=tvState; } /** *开机 */ publicvoidturnOnTv(){ if(!isTvOn){ isTvOn=true; setTvState(newPowerOnState()); System.out.println("--------开机啦---------------"); }else{ isTvOn=true; System.out.println("--------已经开机了,不要再按了---------------"); } } /** *关机 */ publicvoidturnOffTv(){ if(isTvOn){ isTvOn=false; setTvState(newPowerOffState()); System.out.println("--------关机啦---------------"); }else{ isTvOn=false; System.out.println("-------已经关机啦,不要再按了---------------"); } } /** *下一频道 */ publicvoidnextChanel(){ tvState.nextChanel(); } publicvoidpreChanel(){ tvState.preChanel(); } publicvoidturnUp(){ tvState.turnUp(); } publicvoidturnDown(){ tvState.turnDown(); }}

  做一个开机标识,每次调用方法之前进行判断即可。这时再次运行测试类:

  packagecom.state.demo;publicclassTestClass{ publicstaticvoidmain(String[]args){ TvControllertvController=newTvController();//创建一个控制类 tvController.turnOnTv();//首先开机 tvController.turnOnTv();//首先开机 tvController.nextChanel(); tvController.turnDown(); tvController.turnOffTv();//关机 tvController.turnOffTv();//关机 tvController.turnDown();//关机后功能不再提供 }}

  运行如下:

  总结:控制类持有系统状态,但控制类不直接处理行为,行为在状态的实现类中实现;

  用户直接操作控制类,直接和控制类交互,不直接操作状态实现类,这样就有一个职责的分离,有利于系统维护。

  喜欢的朋友请关注我,谢谢。