欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设计模式->行为型模式->状态模式

程序员文章站 2022-06-14 23:27:09
...

1.定义:当一个对象的内部状态改变时允许改变其行为,这个对象看起来像是改变了其类

2.UML

设计模式->行为型模式->状态模式

3.涉及角色

1.抽象状态角色:一般为抽象类或者接口。封装了当前Context的一个特定状态下的相关行为,即一个Context和一个状态关联,该状态决定了具体的行为

2.环境角色:客户端需要的角色并且负责具体状态的切换

主要职责:维护一个Status实例,该实例就是当前的状态.

次要职责:1.将对象设计的状态定义为常量 2.具有抽象状态定义的所有行为(API签名可以一致也可不一致),具体的执行采用委托方式

3.具体状态角色:抽象状态角色子类,该子类有两个职责1.处理当前状态,即当前状态需要处理的逻辑 2.当前状态过渡到下一个状态

4.优点

1.结构清晰,避免了大量的if...else和switch...case语句。将各种状态的转换逻辑转分布到具体的Status中,也就是说将判断逻辑转移到子类中且各个子类明确知道下一状态

2.方便扩展。将特定的状态都放入一个对象中,由于所有和状态相关的逻辑都存在于某个ConcreteStatus子类中通过定义具体的子类就很容易实现增加新状态以及状态转换的功能。

3.遵循开闭原则。通过添加子类增加状态,通过修改具体的子类实现状态的具体处理。

4.封装好,将具体的行为以及状态之间的转换都封装起来,高层模块不知道是如何实现状态和行为的转换

5.将特定状态下对应的行为局部化,并将不同的行为分割处理。

5.缺点

子类膨胀,存在过多的具体状态类。可以采用数据库避免该问题,就是在数据库中添加状态表。

6.使用场景

1.控制一个对象状态转换的条件比较复杂时,把状态的判断逻辑转移到表示不同状态的一系列类中,以简化状态转换判断逻辑

2.一个对象的行为取决于该对象的状态并且需要在运行时根据状态改变自己的行为

3.行为受状态约束的情况,即对象的行为取决于对象的状态且影响较大时,且状态不能太多(小于等于5)

4.大量的分支或者判断的简化。通过扩展子类实现判断或者分枝的转移,但是需要分析当前状态的下一状态

7.Code

模拟电梯运行情况,根据电梯的具体状态改变其行为

抽象状态

public abstract class LiftStatus {

    protected LiftContext liftContext;

    protected void setLiftContext(LiftContext liftContext) {
        this.liftContext = liftContext;
    }

    //open可以转换到close
    //0 close
    public abstract void open(int status);

    //run可以转换到stop
    public abstract void run(int status);

    //close可以转换到run / open / stop
    //1 : run 2 : open 3 : stop
    public abstract void close(int status);

    //stop 可以转换到open / run
    //1 : run 3 : stop
    public abstract void stop(int status);
}
具体状态--openDoor

//open状态下只能关闭
public class OpenDoorStatus extends LiftStatus{

    @Override
    public void open(int status) {
        if (LiftContext.CLOSE == status) {
            this.close(status);
        } else {
            //实现当前状态下对象的逻辑
            System.out.println("Status open");
        }
    }

    @Override
    public void run(int status) {
        //do nothing
    }

    @Override
    public void close(int status) {
        //设置下一个状态
        super.liftContext.setStatus(LiftContext.closeDoor);
        super.liftContext.close(status);
    }

    @Override
    public void stop(int status) {
        //do nothing
    }
}
具体状态--CloseDoor

//close状态下可以转换为 run, stop, open
public class CloseDoorStatus extends LiftStatus{

    @Override
    public void open(int status) {
        super.liftContext.setStatus(LiftContext.openDoor);
        super.liftContext.open(status);
    }

    @Override
    public void run(int status) {
        super.liftContext.setStatus(LiftContext.run);
        super.liftContext.run(status);
    }

    @Override
    public void close(int status) {
        if (LiftContext.RUN == status) {
            this.run(status);
        } else if (LiftContext.STOP == status) {
            this.stop(status);
        } else if (LiftContext.OPEN == status) {
            this.open(status);
        } else {
            //实现当前状态下对象的逻辑
            System.out.println("Status close");
        }
    }

    @Override
    public void stop(int status) {
        super.liftContext.setStatus(LiftContext.stop);
        super.liftContext.stop(status);
    }
}
具体状态--Run

//run状态下只能stop
public class RunStatus extends LiftStatus{

    @Override
    public void open(int status) {
        //do nothing
    }

    @Override
    public void run(int status) {
        if (LiftContext.STOP == status) {
            this.stop(status);
        } else {
            //实现当前状态下对象的逻辑
            System.out.println("Status run");
        }
    }

    @Override
    public void close(int status) {
        //do nothing
    }

    @Override
    public void stop(int status) {
        super.liftContext.setStatus(LiftContext.stop);
        super.liftContext.stop(status);
    }
}
具体状态--Stop
//stop状态下可以转换为open , run
public class StopStatus extends LiftStatus{

    @Override
    public void open(int status) {
        super.liftContext.setStatus(LiftContext.openDoor);
        super.liftContext.open(status);
    }

    @Override
    public void run(int status) {
        super.liftContext.setStatus(LiftContext.run);
        super.liftContext.run(status);
    }

    @Override
    public void close(int status) {
        //do nothing
    }

    @Override
    public void stop(int status) {
        if (LiftContext.OPEN == status) {
            this.open(status);
        } else if (LiftContext.RUN == status) {
            this.run(status);
        } else {
            //实现当前状态下对象的逻辑
            System.out.println("Status stop");
        }
    }
}
环境角色

public class LiftContext {
    //对象对应的各个状态
    public static final OpenDoorStatus openDoor = new OpenDoorStatus();
    public static final CloseDoorStatus closeDoor = new CloseDoorStatus();
    public static final RunStatus run = new RunStatus();
    public static final StopStatus stop = new StopStatus();


    //定义具体状态常量
    public static final int CLOSE = 0;
    public static final int RUN = 1;
    public static final int OPEN = 2;
    public static final int STOP = 3;

    private LiftStatus status;

    public LiftContext(LiftStatus status) {
        this.status = status;
        //将当前环境通知到具体的实现类中
        this.status.setLiftContext(this);
    }

    public LiftStatus getStatus() {
        return status;
    }

    public void setStatus(LiftStatus status) {
        this.status = status;
        //将当前环境通知到具体的实现类中
        this.status.setLiftContext(this);
    }

    public void open(int status) {
        this.status.open(status);
    }

    public void run(int status) {
        this.status.run(status);
    }

    public void close(int status) {
        this.status.close(status);
    }

    public void stop(int status) {
        this.status.stop(status);
    }
}

客户端

public class Client {
    public static void main(String[] args) {
        LiftContext context = new LiftContext(new CloseDoorStatus());
        context.close(LiftContext.CLOSE);
        context.close(LiftContext.OPEN);
        context.close(LiftContext.RUN);
        context.close(LiftContext.STOP);
//        context.open(LiftContext.CLOSE);
//        context.close(LiftContext.RUN);
//        context.run(LiftContext.STOP);
//        context.stop(LiftContext.OPEN);
    }
}