状态模式【State Pattern】

一个简单的电梯状态模型 题目: "简易电梯控制系统" 大家日常生活中经见到的电梯。 你有没有想过它的内部运行机制和实现方法。现在大家就共同讨论一下电梯到底是怎么运行的。 1. 尝试画出你心目中的电梯系统架构图。大胆show出你的想法。 2. 画出电梯运行过程中的状态转换图(停止,上升,下降,开门,报警等),电梯运行的流程图。 阅读详情

       现在城市发展很快,百万级人口的城市一堆一堆的,那其中有两个东西的发明在城市的发展中起到非常重要的作用:一个是汽车,一个呢是...,猜猜看,是什么?是电梯!汽车让城市可以横向扩展,电梯让城市可以纵向延伸,向空中伸展。汽车对城市的发展我们就不说了,电梯,你想想看,如果没有电梯,每天你需要爬 10 层楼梯,你是不是会崩溃掉?建筑师设计了一个没有电梯的建筑,那投资家肯定不愿意投资,那也是建筑师的耻辱呀,今天我们就用程序表现一下这个电梯是怎么运作的。

       我们每天都在乘电梯,那我们来看看电梯有哪些动作(映射到 Java 中就是有多少方法):开门、关门、运行、停止,就这四个动作,好,我们就用程序来实现一下电梯的动作,先看类图设计:


非常简单的类图,定义一个接口,然后是一个实现类,然后业务类 Client 就可以调用,并运行起来,简单也来看看我们的程序,先看接口:

package com.cbf4life.common;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 定义一个电梯的接口
*/
public interface ILift {

//首先电梯门开启动作
public void open();

//电梯门有开启,那当然也就有关闭了
public void close();

//电梯要能上能下,跑起来
public void run();

//电梯还要能停下来,停不下来那就扯淡了
public void stop();
} 
然后看实现类: 
package com.cbf4life.common;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 电梯的实现类
*/
public class Lift implements ILift {
//电梯门关闭
public void close() {
 System.out.println("电梯门关闭...");
 }

//电梯门开启
public void open() {
 System.out.println("电梯门开启...");
 }

//电梯开始跑起来
public void run() {
 System.out.println("电梯上下跑起来...");
 }
//电梯停止
public void stop() {
 System.out.println("电梯停止了...");
 }
} 
电梯的开、关、跑、停都实现了,开看业务是怎么调用的:
package com.cbf4life.common;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 模拟电梯的动作
*/
public class Client {

public static void main(String[] args) {
 ILift lift = new Lift();
 //首先是电梯门开启,人进去
 lift.open();

 //然后电梯门关闭
 lift.close();

 //再然后,电梯跑起来,向上或者向下
 lift.run();

 //最后到达目的地,电梯挺下来
 lift.stop();
 }
}
运行的结果如下:
电梯门开启...
电梯门关闭...
电梯上下跑起来...
电梯停止了... 
       太简单的程序了,是个程序员都会写这个程序,这么简单的程序还拿出来 show,是不是太小看我们的智商了?!非也,非也,我们继续往下分析,这个程序有什么问题,你想呀电梯门可以打开,但不是随时都可以开,是有前提条件的的,你不可能电梯在运行的时候突然开门吧?!电梯也不会出现停止了但是不开门的情况吧?!那要是有也是事故嘛,再仔细想想,电梯的这四个动作的执行都是有前置条件,具体点说说在特定状态下才能做特定事,那我们来分析一下电梯有什么那些特定状态:
       门敞状态---按了电梯上下按钮,电梯门开,这中间有 5 秒的时间(当然你也可以用身体挡住电梯门,那就不是 5 秒了),那就是门敞状态;在这个状态下电梯只能做的动作是关门动作,做别的动作?那就危险喽

       门闭状态---电梯门关闭了,在这个状态下,可以进行的动作是:开门(我不想坐电梯了)、停止(忘记按路层号了)、运行

       运行状态---电梯正在跑,上下窜,在这个状态下,电梯只能做的是停止;

       停止状态---电梯停止不动,在这个状态下,电梯有两个可选动作:

       继续运行和开门动作;我们用一张表来表示电梯状态和动作之间的关系:


看到这张表后,我们才发觉,哦~~,我们的程序做的很不严谨,好,我们来修改一下,先看类图:


       在接口中定义了四个常量,分别表示电梯的四个状态:门敞状态、关闭状态、运行状态、停止状态,然后在实现类中电梯的每一次动作发生都要对状态进行判断,判断是否运行执行,也就是动作的执行是否符合业务逻辑,实现类中的四个私有方法是仅仅实现电梯的动作,没有任何的前置条件,因此这四个方法是不能为外部类调用的,设置为私有方法。我们先看接口的改变:

package com.cbf4life.common2;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 定义一个电梯的接口
*/
public interface ILift {
//电梯的四个状态
public final static int OPENING_STATE = 1; //门敞状态
public final static int CLOSING_STATE = 2; //门闭状态
public final static int RUNNING_STATE = 3; //运行状态
public final static int STOPPING_STATE = 4; //停止状态;

//设置电梯的状态
public void setState(int state);

//首先电梯门开启动作
public void open();

//电梯门有开启,那当然也就有关闭了
public void close();

//电梯要能上能下,跑起来
public void run();

//电梯还要能停下来,停不下来那就扯淡了
public void stop();
} 
增加了四个静态常量,增加了一个方法 setState,设置电梯的状态。我们再来看实现类是如何实现的:
package com.cbf4life.common2;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 电梯的实现类
*/
public class Lift implements ILift {
private int state;

public void setState(int state) {
 this.state = state;
 } 
//电梯门关闭
public void close() {
 //电梯在什么状态下才能关闭
 switch(this.state){
 case OPENING_STATE: //如果是则可以关门,同时修改电梯状态
 this.closeWithoutLogic();
 this.setState(CLOSING_STATE);
 break;
 case CLOSING_STATE: //如果电梯就是关门状态,则什么都不做
 //do nothing;
 break;
 case RUNNING_STATE: //如果是正在运行,门本来就是关闭的,也说明都不做
 //do nothing;
 break;
 case STOPPING_STATE: //如果是停止状态,本也是关闭的,什么也不做
 //do nothing;
 break;
 }

 }

//电梯门开启
public void open() {
 //电梯在什么状态才能开启
 switch(this.state){
 case OPENING_STATE: //如果已经在门敞状态,则什么都不做
 //do nothing;
 break;
 case CLOSING_STATE: //如是电梯时关闭状态,则可以开启
 this.openWithoutLogic();
 this.setState(OPENING_STATE);
 break;
 case RUNNING_STATE: //正在运行状态,则不能开门,什么都不做
 //do nothing;
 break;
 case STOPPING_STATE: //停止状态,淡然要开门了
 this.openWithoutLogic();
 this.setState(OPENING_STATE);
 break;
 }
 }
//电梯开始跑起来 
public void run() {
 switch(this.state){
 case OPENING_STATE: //如果已经在门敞状态,则不你能运行,什么都不做
 //do nothing;
 break;
 case CLOSING_STATE: //如是电梯时关闭状态,则可以运行
 this.runWithoutLogic();
 this.setState(RUNNING_STATE);
 break;
 case RUNNING_STATE: //正在运行状态,则什么都不做
 //do nothing;
 break;
 case STOPPING_STATE: //停止状态,可以运行
 this.runWithoutLogic();
 this.setState(RUNNING_STATE);
 }
 }
//电梯停止
public void stop() {
 switch(this.state){
 case OPENING_STATE: //如果已经在门敞状态,那肯定要先停下来的,什么都不做
 //do nothing;
 break;
 case CLOSING_STATE: //如是电梯时关闭状态,则当然可以停止了
 this.stopWithoutLogic();
 this.setState(CLOSING_STATE);
 break;
 case RUNNING_STATE: //正在运行状态,有运行当然那也就有停止了
 this.stopWithoutLogic();
 this.setState(CLOSING_STATE);
 break;
 case STOPPING_STATE: //停止状态,什么都不做
 //do nothing;
 break;
 }
 }
//纯粹的电梯关门,不考虑实际的逻辑
private void closeWithoutLogic(){
 System.out.println("电梯门关闭...");
 }
//纯粹的店门开,不考虑任何条件
private void openWithoutLogic(){
 System.out.println("电梯门开启...");
 }
//纯粹的运行,不考虑其他条件
private void runWithoutLogic(){
 System.out.println("电梯上下跑起来...");
 }
//单纯的停止,不考虑其他条件
private void stopWithoutLogic(){
 System.out.println("电梯停止了...");
 }
} 
程序有点长,但是还是很简单的,就是在每一个接口定义的方法中使用 witch…case 来进行判断,是否运行运行指定的动作。我们来 Client 程序的变更:
package com.cbf4life.common2;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 模拟电梯的动作
*/
public class Client {

public static void main(String[] args) {
 ILift lift = new Lift();

 //电梯的初始条件应该是停止状态
 lift.setState(ILift.STOPPING_STATE);

 //首先是电梯门开启,人进去
 lift.open();

 //然后电梯门关闭
 lift.close();

 //再然后,电梯跑起来,向上或者向下
 lift.run();
 //最后到达目的地,电梯挺下来
 lift.stop();
 }
} 
业务调用的方法中增加了电梯状态判断,电梯要开门不是随时都可以开的,必须满足了一定条件你才能开门,人才能走进去,我们设置电梯的起始是停止状态,看运行结果:
电梯门开启...
电梯门关闭...
电梯上下跑起来...
电梯停止了... 
        我们来想一下,这段程序有什么问题,首先 Lift.java 这个文件有点长,长的原因是我们在程序中使用了大量的 switch…case 这样的判断(if…else 也是一样),程序中只要你有这样的判断就避免不了加长程序,同步的在业务比较复杂的情况下,程序体会更长,这个就不是一个很好的习惯了,较长的方法或者类的维护性比较差,毕竟程序是给人来阅读的;其次,扩展性非常的不好,大家来想想,电梯还有两个状态没有加,是什么?通电状态和断电状态,你要是在程序再增加这两个方法,你看看 Open()、Close()、Run()、Stop()这四个方法都要增加判断条件,也就是说 switch 判断体中还要增加 case 项,也就说与开闭原则相违背了;再其次,我们来思考我们的业务,电梯在门敞开状态下就不能上下跑了吗?电梯有没有发生过只有运行没有停止状态呢(从 40 层直接坠到 1 层嘛)?电梯故障嘛,还有电梯在检修的时候,可以在 stop状态下不开门,这也是正常的业务需求呀,你想想看,如果加上这些判断条件,上面的程序有多少需要修改?虽然这些都是电梯的业务逻辑,但是一个类有且仅有一个原因引起类的变化,单一职责原则,看看我们的类,业务上的任务一个小小增加或改动都对我们的这个电梯类产生了修改,这是在项目开发上是有很大风险的。既然我们已经发现程序上有以上问题,我们怎么来修改呢?
       刚刚我们是从电梯的有哪些方法以及这些方法执行的条件去分析,现在我们换个角度来看问题,我们来想电梯在具有这些状态的时候,能够做什么事情,也就是说在电梯处于一个具体状态时,我们来思考这个状态是由什么动作触发而产生以及在这个状态下电梯还能做什么事情,举个例子来说,电梯在停止状态时,我们来思考两个问题:

       第一、这个停止状态时怎么来的,那当然是由于电梯执行了 stop 方法而来的;

       第二、在停止状态下,电梯还能做什么动作?继续运行?开门?那当然都可以了。

       我们再来分析其他三个状态,也都是一样的结果,我们只要实现电梯在一个状态下的两个任务模型就可以了:这个状态是如何产生的以及在这个状态下还能做什么其他动作(也就是这个状态怎么过渡到其他状态),既然我们以状态为参考模型,那我们就先定义电梯的状态接口,思考过后我们来看类图:


在类图中,定义了一个 LiftState 抽象类,声明了一个受保护的类型 Context 变量,这个是串联我们各个状态的封装类,封装的目的很明显,就是电梯对象内部状态的变化不被调用类知晓,也就是迪米特法则了,我的类内部情节你知道越少越好,并且还定义了四个具体的实现类,承担的是状态的产生以及状态间的转换过渡,我们先来看 LiftState 程序:

package com.cbf4life.advance;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 定义一个电梯的接口
*/
public abstract class LiftState{
//定义一个环境角色,也就是封装状态的变换引起的功能变化
protected Context context;

public void setContext(Context _context){
 this.context = _context;
 } 
//首先电梯门开启动作
public abstract void open();

//电梯门有开启,那当然也就有关闭了
public abstract void close();

//电梯要能上能下,跑起来
public abstract void run();

//电梯还要能停下来,停不下来那就扯淡了
public abstract void stop();

} 
抽象类比较简单,我们来先看一个具体的实现,门敞状态的实现类:
package com.cbf4life.advance;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 在电梯门开启的状态下能做什么事情
*/
public class OpenningState extends LiftState {
//开启当然可以关闭了,我就想测试一下电梯门开关功能
@Override
public void close() {
 //状态修改
 super.context.setLiftState(Context.closeingState);
 //动作委托为CloseState来执行
 super.context.getLiftState().close();
 }
//打开电梯门
@Override
public void open() {
 System.out.println("电梯门开启...");
 }

//门开着电梯就想跑,这电梯,吓死你!
@Override
public void run() { 
 //do nothing;
 }
//开门还不停止?
public void stop() {
 //do nothing;
 }
} 
        我来解释一下这个类的几个方法,Openning 状态是由 open()方法产生的,因此这个方法中有一个具体的业务逻辑,我们是用 print 来代替了;在 Openning 状态下,电梯能过渡到其他什么状态呢?按照现在的定义的是只能过渡到 Closing 状态,因此我们在 Close()中定义了状态变更,同时把 Close 这个动作也委托了给 CloseState 类下的 Close 方法执行,这个可能不好理解,我们再看看 Context 类就可能好理解一点:
package com.cbf4life.advance;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
*/
public class Context {
//定义出所有的电梯状态
public final static OpenningState openningState = new OpenningState();
public final static ClosingState closeingState = new ClosingState();
public final static RunningState runningState = new RunningState();
public final static StoppingState stoppingState = new StoppingState();

//定一个当前电梯状态
private LiftState liftState;

public LiftState getLiftState() {
 return liftState;
 }
public void setLiftState(LiftState liftState) {
 this.liftState = liftState;
 //把当前的环境通知到各个实现类中
 this.liftState.setContext(this);
 }
public void open(){
 this.liftState.open();
 }

public void close(){
 this.liftState.close();
 }

public void run(){
 this.liftState.run();
 }

public void stop(){
 this.liftState.stop();
 }
} 
       结合以上三个类,我们可以这样理解,Context 是一个环境角色,它的作用是串联各个状态的过渡,在LiftSate 抽象类中我们定义了并把这个环境角色聚合进来,并传递到了子类,也就是四个具体的实现类中自己根据环境来决定如何进行状态的过渡。我们把其他的三个具体实现类阅读完毕,下面是关闭状态:
package com.cbf4life.advance;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 电梯门关闭以后,电梯可以做哪些事情
*/
public class ClosingState extends LiftState {
//电梯门关闭,这是关闭状态要实现的动作
@Override
public void close() {
 System.out.println("电梯门关闭...");
 }
//电梯门关了再打开,逗你玩呢,那这个允许呀
@Override
public void open() {
 super.context.setLiftState(Context.openningState); //置为门敞状态
 super.context.getLiftState().open(); 
 }
//电梯门关了就跑,这是再正常不过了
@Override
public void run() {
 super.context.setLiftState(Context.runningState); //设置为运行状态;
 super.context.getLiftState().run();
 }
//电梯门关着,我就不按楼层
@Override
public void stop() {
 super.context.setLiftState(Context.stoppingState); //设置为停止状态;
 super.context.getLiftState().stop();
 }

} 
下面是电梯的运行状态:
package com.cbf4life.advance;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 电梯在运行状态下能做哪些动作
*/
public class RunningState extends LiftState {

//电梯门关闭?这是肯定了
@Override
public void close() {
 //do nothing
 }
//运行的时候开电梯门?你疯了!电梯不会给你开的
@Override
public void open() {
 //do nothing
 }
//这是在运行状态下要实现的方法
@Override
public void run() {
 System.out.println("电梯上下跑...");
 }
//这个事绝对是合理的,光运行不停止还有谁敢做这个电梯?!估计只有上帝了
@Override
public void stop() {
 super.context.setLiftState(Context.stoppingState); //环境设置为停止状态;
 super.context.getLiftState().stop();
 }
} 
下面是停止状态:
package com.cbf4life.advance;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 在停止状态下能做什么事情
*/
public class StoppingState extends LiftState {

//停止状态关门?电梯门本来就是关着的!
@Override
public void close() {
 //do nothing;
 }
//停止状态,开门,那是要的!
@Override
public void open() {
 super.context.setLiftState(Context.openningState);
 super.context.getLiftState().open();
 }
//停止状态再跑起来,正常的很
@Override
public void run() {
 super.context.setLiftState(Context.runningState);
 super.context.getLiftState().run();
 } 
//停止状态是怎么发生的呢?当然是停止方法执行了
@Override
public void stop() {
 System.out.println("电梯停止了...");
 }
} 
业务逻辑都已经实现了,我们来看看 Client 怎么实现:
package com.cbf4life.advance;
/**
* @author cbf4Life cbf4life@126.com
* I'm glad to share my knowledge with you all.
* 模拟电梯的动作
*/
public class Client {

public static void main(String[] args) {
 Context context = new Context();
 context.setLiftState(new ClosingState());

 context.open();
 context.close();
 context.run();
 context.stop();
 }
}
  Client 调用类太简单了,只要定义个电梯的初始状态,然后调用相关的方法,就完成了,完全不用考虑状态的变更,看运行结果:
电梯门开启...
电梯门关闭...
电梯上下跑起来...
电梯停止了... 
      我们再来回顾一下我们刚刚批判上一段的代码,首先我们说人家代码太长,这个问题我们解决了,通过各个子类来实现,每个子类的代码都很短,而且也取消了的 switch…case 条件的判断;其次,说人家不符合开闭原则,那如果在我们这个例子中要增加两个状态怎么加?增加两个子类,一个是通电状态,一个是断电状态,同时修改其他实现类的相应方法,因为状态要过渡呀,那当然要修改原有的类,只是在原有类中的方法上增加,而不去做修改;再其次,我们说人家不符合迪米特法则,我们现在呢是各个状态是单独的一个类,只有与这个状态的有关的因素修改了这个类才修改,符合迪米特法则,非常完美!
        上面例子中多次提到状态,那我们这节讲的就是状态模式,什么是状态模式呢?当一个对象内在状态改变时允许其改变行为,这个对象看起来像是改变了其类。说实话,这个定义的后半句我也没看懂,看过GOF 才明白是怎么回事: Allow an object to alter its behavior when its internal state changes. Theobject will appear to change its class. [GoF, p305],也就是说状态模式封装的非常好,状态的变更引起了行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。状态模式的通用实现类如下:

        状态模式中有什么优点呢?首先是避免了过多的 swith…case 或者 if..else 语句的使用,避免了程序的复杂性;其次是很好的使用体现了开闭原则和单一职责原则,每个状态都是一个子类,你要增加状态就增加子类,你要修改状态,你只修改一个子类就可以了;最后一个好处就是封装性非常好,这也是状态模式的基本要求,状态变换放置到了类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。

        状态模式既然有优点,那当然有缺点了,只有一个缺点,子类会太多,也就是类膨胀,你想一个事物有七八、十来个状态也不稀奇,如果完全使用状态模式就会有太多的子类,不好管理,这个需要大家在项目自己衡量。其实有很大方式解决这个状态问题,比如在数据库中建立一个状态表,然后根据状态执行相应的操作,这个也不复杂,看大家的习惯和嗜好了。

       状态模式使用于当某个对象在它的状态发生改变时,它的行为也随着发生比较大的变化,也就是说行为是受状态约束的情况下可以使用状态模式,而且状态模式使用时对象的状态最好不要超过五个,防止你写子类写疯掉。

       上面的例子可能比较复杂,请各位看官耐心的看,看完我想肯定有所收获。我翻遍了所有能找的到的资料(至少也有十几本,其中有几本原文的书还是很的很不错的,我举这个电梯的例子也是从《DesignPattern for Dummies》这本书来激发出来的),基本(基本哦,还是有几本讲的不错)上没有一本把这个状态模式讲透彻的,我不敢说我就讲的透彻,大家都只讲了一个状态到另一个状态过渡,状态间的过渡是固定的,举个简单的例子:


        这个状态图是很多书上都有的,状态 A 只能变更到状态 B,状态 B 再变更到状态 C,例子举的最多的就是 TCP 监听的例子,TCP 有三个状态:等待,连接,断开,然后这三个状态中按照顺序循环变更,按照这个状态变更来讲解状态模式,我认为是不太合适的,为什么呢?你在项目中太少看到一个状态只能过渡到另一个状态情形,项目中遇到的大多数情况都是一个状态可以转换为几种状态,如下图:


       状态 B 可以转换为状态 C 也可以转换为状态 D,而状态 D 呢也可以转换为状态 A 或状态 B,这在项目分析过程中有一个叫状态图可以完整的展示这种蜘蛛网结构,举个实际例子来说,一些收费网站的用户就有很多状态,比如普通用户,普通会员,VIP 会员,白金级用户等等,这个状态的变更你不允许跳跃?!这不可能,所以我在例子中就举了一个比较复杂的应用,基本上可以实现状态间自由切换,这才是最经常用到的状态模式。然后我再提问个问题,状态间的自由切换,那会有很多种呀,你要一个一个的牢记一遍吗?比如上面那个电梯的例子,我要一个正常的电梯运行逻辑,规则是开门->关门->运行->停止;还要一个紧急状态(比如火灾)下的运行逻辑,关门->停止,紧急状态电梯当然不能用了;再要一个维修状态下的运行逻辑,这个状态任何情况都可以,开着门电梯运行?可以!门来回开关?可以!永久停止不动?可以! 那这怎么实现呢?需要我们把已经有的几种状态按照一定的顺序再重新组装一下,那这个是什么模式?什么模式?大声点!建造者模式!对,建造模式+状态模式会起到非常好的封装作用。

        再往深里面扯几句,应该有部分读者做过工作流开发,如果不是土制框架的话,就应该有个状态机管理(即使是土制框架也应该有),比如一个 Activity(节点)有初始化状态(Initialized State)、挂起状态(Suspended State)、完成状态(Completed State)等等,流程实例也是有这么多状态,那这些状态怎么管理呢?通过状态机(State Machine)来管理,那状态机是个什么东西呢?就是我们上面提到的 Context类的升级变态 BOSS!


状态模式(State Pattern)详解 状态模式是一种行为设计模式,它允许对象在内部状态改变时改变它的行为。这种模式将状态相关的行为抽取到独立的状态类中,使得代码更加清晰、可维护,并且可以在运行时自由切换对象的状态。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的上下文对象。消除了复杂的条件分支语句提高了代码的可维护性和可扩展性使状态转换更加明确,减少了出错可能符合开闭原则,便于添加新状态。 阅读详情

相关推荐

状态模式实例(电梯)

能让你迅速理解和运用设计模式中的状态模式,进行编程

状态模式

        文档地址:《设计模式之禅》​​​​​​​         切入故事: 城市的纵向发展功臣——电梯         定义: Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.(当一个对象内在状态改变时允许其...

Jerome的博客 247

智能车八邻域图像算法_二

智能车八邻域图像算法 文章目录智能车八邻域图像算法前言一、一些想法二、生长方向的使用1.点的生长方向的表示2. 用点的生长方向来做初步判断1.引入库2.读入数据总结 前言 上一篇里面讲过用八邻域来获得赛道边界:智能车八邻域图像算法 当已经能稳定获得赛道边界时,就可以进行元素识别,获得偏差了。 这里就介绍一下我的一些思路。 早在前两年,优快云上就有一篇关于八邻域如何处理元素的文章第十五届全国大学生智能汽车竞赛-双车组三轮图像处理总结,写得很好,我当时也参考了这篇文章,但是我觉得不是很详细,所以我这里想写得

技术缝合怪的博客 1万+

设计模式-状态模式

今天学习了状态模式,做个总结。 本文多出摘选自《设计模式之禅》,只留作学习复习只用。 为了更好地了解学习状态模式,先认识一个小例子——电梯。 举个例子 电梯大家应该都很熟悉,日常生活用得到,电梯的日常上下路逻辑大家应该也很熟悉,就比如我们每个人去坐电梯,一个最简单最基础的流程是: 一个人来到电梯前按按钮上下楼——>电梯开门——>进去关上门按按钮——>电梯运行向上向下——>到达目的楼层,电梯停止。 在上边的一个基本流程中,包含了开门,关门,停止,运行四个基本动作,包含了...

张大帅的博客 7294

国家医保移动支付国密算法SM2签名验签、SM4加解密DLL

DLL,非.net开发,所以无需安装配置,直接程序引用开发即可,支持各类开发语言。已知省份有广西、贵州、安徽、河北、黑龙江、湖南、吉林、江苏、四川、新疆等各地方。国家医保移动支付国密算法SM2签名验签、SM4加解密DLL。//SM4加密与解密。支持医保移动支付(国家统一版),//SM2签名与验签。

4264

開機自動進入UEFI Interactive Shell無法正常開機怎麼辦?

BIOS/UEFI,啟動後進入UEFI Interactive Shell大多數人都告訴你沒有安裝系統去裝系統吧,但你明明昨天還在運行系統?今天就這樣?有沒有解決辦法?

sheaahhoi1的博客 7742

设计模型之状态模式含UML完整实例)

设计模型之状态模式 1. 状态模式   什么是状态模式?以电梯为例。电梯的状态有停止、运行、开门和关门等状态。而且每个状态还都要有特定的行为,比如在开门的状态下,电梯只能关门,而不能运行;在关门状态下,电梯可以运行、开门等。用一张表来表示这个关系: 电梯 开门 关门 运行 停止 开门状态 × √ × × 关门状态 √ × √ × 运行状态 × × × √ 停止状态 √ ...

atu1111的博客 2577

《统计学习方法》——李航 学习大纲

最近在学习李航写的统计学习方法概论, 每一章都用xmind理清了思路,括号里是书里的公式,第一次写博文,敬请指教~~~~ 第一章 统计学习方法论 第二章 感知机 每个方法其实只需要着重掌握三要素和输入输出就可以了,主要看模型、策略和算法。 感知机主要是二类分类的线性分类模型。 看到后面会注意感知机和支持向量机的区别。 第三章 k近

wjy619251334的博客 1万+

设计模式,状态模式:电梯先关门后移动,c++实现

状态模式:电梯想要移动首先得是关门的。 定义:当一个对象内在状态改变时,允许其改变行为,这个对象看起来像改变了其类。 翻译:就是没有某个状态,就不能做出某行为。因为类的动作一般是在任何情况下都可以调用的,受到状态的限制后,就像是基于不同的状态而换了不同的类一样,对着状态机理解就可。 类图摘自设计模式之禅: state抽象状态角色,接口或抽象类: 负责对象状态定义,封装环境角色以实现状态切换。 封装对象的所有功能函数,已满足实现不同的状态。 concretestate具体状态角色,两个职责: 本状态的行为管

ganfanren00001的博客 752

从光斑图到锤形优化:一次搞定Zemax双胶合透镜的像散与场曲问题

本文详细解析了Zemax双胶合透镜设计中像散与场曲问题的诊断与优化方法。从光斑图分析到锤形优化技巧,提供了完整的光学设计实战指南,帮助设计师快速定位问题并有效改善系统性能,特别适合光学设计工程师和Zemax使用者参考。

weixin_27134495的博客 233

【数据分享】1985-2023年30米CLCD土地覆盖栅格数据分享

总的来说,CLCD 反映了中国快速的城市化进程和一系列生态工程,揭示了气候变化条件下人为对 LC的影响,其在全球变化研究中具有潜在应用价值。最后,通过目视解译的独立样本和第三方测试样本评估CLCD的准确性。特别地,该研究将CLCD产品与目前最先进的30m专题产品包括不透水表面积(ISA)、地表水和森林进行比对,以综合评估CLCD的质量(以下为技术流程图)。数据分类:分为九类用地,该数据包括9种用地类型,分别为:农田、森林、灌木、草原、水域、冰雪、裸地、不透水面、湿地。数据格式:.tif格式。

weixin_61129400的博客 6924

设计模式24:State Pattern (状态模式)

英文原文:http://www.dofactory.com/Patterns/PatternState.aspx一、State Pattern (状态模式)Define: Allow an object to alter its behavior when its internal state changes. The object will appear to change its cl

薛敬明的专栏 1897

单光子雪崩二极管(SPAD):原理、极高增益机制与微光探测解析

本文系统阐述了单光子雪崩二极管(SPAD)的工作原理及其在弱光探测中的应用。SPAD通过工作在盖革模式下的碰撞离化效应实现单光子探测,其核心机理包括:1)采用p+-n-n+结构实现高电场分布;2)通过雪崩倍增过程获得10^6量级增益;3)采用主动/被动淬灭机制实现快速恢复。文章详细分析了SPAD的关键性能参数(如光子探测效率、暗计数率等)及其在量子通信、激光雷达等领域的应用优势,揭示了该器件在极微弱光信号探测中的独特价值。

Fun_LiDAR的博客 1043

状态模式(State Pattern)

也称为状态机模式(State Machine Pattern)通过定义不同的状态类来封装与特定状态相关的行为,并将状态的判断逻辑转移到表示不同状态的一系列类中,从而把复杂的判断逻辑简化。状态模式将状态和行为分开,使对象在内部状态改变时能够改变它的行为。每一个状态对应一个子类,从而将状态的转换逻辑分布到状态子类中,减少了相互依赖。客户端通常不直接与状态对象交互,而是通过环境类(Context)与状态对象进行交互。

yuiezt的专栏 677

2025B卷最新华为OD机试持续收录中 - 真题题库清单,按考点划分(Python / JS / C++ / JAVA / C语言)

2025B卷最新华为OD机试持续收录中 - 真题题库清单,按考点划分(Python / JS / C++ / JAVA / C语言)

算法大师! 3057

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

状态模式-State Pattern

在软件开发过程中,应用程序中的有些对象可能会根据不同的情况做出不同的行为,我们把这种对象称为有状态的对象,而把影响对象行为的一个或多个动态变化的属性称为状态。当有状态的对象与外部事件产生互动时,其内部状态会发生改变,从而使得其行为也随之发生改变。如人的情绪有高兴的时候和伤心的时候,不同的情绪有不同的行为,当然外界也会影响其情绪变化。 对这种有状态的对象编程,传统的解决方案是:将这些所有可能发生的...

心猿意碼 4163

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

设计模式 状态模式(State Pattern)

状态模式(State Pattern)flyfish#include "stdafx.h" #include class role; class employee { public: virtual void output(role *role_ptr) = 0;};class engineer : public employee {public: virtua

二分掌柜的 838

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

java state用法博客园_状态模式-State Pattern(Java实现)

状态模式-State Pattern在状态模式(StatePattern)中,类的行为是基于它的状态改变的。当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。State接口表明状态, 实体类是根据状态的变化而发生响应行为的变化的./*** 状态抽象定义*/public interface State {void onEnterState();void observe();}...

weixin_29137997的博客 206

State Pattern 状态模式

State Pattern: allows an object to alter its behavior when its internal state changes. The object will appear to changes its class. Encapsulate state into separate classes. With the State Pattern, we

Geurney的专栏 597

设计模式:状态模式(State Pattern)

/** * 状态模式。 * @author Bright Lee */ public class StatePattern { public static void main(String[] args) { Context context = new Context(); context.request(); context.request(); } } cla...

look4liming的专栏 249

状态模式State Pattern

状态模式(State Pattern)是一种对象行为型模式,它主要解决的是一个对象在其内部状态发生改变时会导致其行为的变化,通过将状态封装成独立的对象,可以使得状态的变化独立于对象的行为,从而实现状态和行为之间的解耦。状态模式通常包含以下角色:Context(上下文):定义客户端感兴趣的接口,维护一个对具体状态类的实例,以便于客户端调用具体状态类的方法。State(抽象状态):定义一个接口以封装与Context的一个特定状态相关的行为。ConcreteState(具体状态):实现State接口。

qq_34893654的博客 215

【状态模式】 State Pattern

我们先设计一个场景,饮料自动售卖机,来设计一下它的出售流程。 流程图中,我们可把这个过程看成几个状态: 投币状态,选择饮料状态,售出状态,出售完毕状态. ,有了这个四个状态,我们设计一下界面(很粗略): 在这里我们只定义了三种饮料和一个投币口,在设计接口和类之前,我们来看一下状态模式的UML图: State接口定义了一个所有具体状态的共同接口;任何状态都实...

weixin_34380781的博客 303
上一篇: 访问者模式【Visitor Pattern】
下一篇: 原型模式【Prototype Pattern】
涛濤
博客等级 码龄12年 136粉丝 92原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值