状态模式 订阅
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类 展开全文
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类
信息
外文名
State
中文名
状态模式
状态模式状态模式
(State Pattern)是设计模式的一种,属于行为模式。
收起全文
精华内容
下载资源
问答
  • 状态模式

    千次阅读 2021-06-13 09:45:43
    状态模式:主要用来解决对象在多种状态转换时需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换。当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像改变了其类。 举例:人...
    状态模式:主要用来解决对象在多种状态转换时需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换。当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像改变了其类。

    举例:人的一生。小的时候(假设是0~7岁)只能当幼儿园学生;青年时(假设是7 ~ 18岁)可以当初中和高中生,相应可以做的事情也变多了;成年时,可以做大学生,硕士生等等,做的事情变得更多了。

    • 状态模式的关键是将对象的状态封装称为独立的类,对象调用方法时,可以委托当前对象所具有的状态调用相应的方法,是当前对象看起来好像是修改了它的类。

    角色说明:

    • 环境( Context ):环境是一个类,该类含有抽象状态声明的变量,可以引用任何具体状态类的实例。用户对该环境类的实例在某种状态下的行为感兴趣。
    • 抽象状态( State ):抽象状态是一个接口或抽象类。抽象状态中定义了与环境的一个特定状态相关的若干个方法。
    • 具体状态( Concrete State ):具体状态是实现( 扩展 )抽象状态( 抽象类 )的类。
    “普通” 状态模式案例

    Thermometer.java

    public class Thermometer { // 环境
    	TemperatureState state;
    	public void showMessage() {
    		System.out.println("*********");
    		state.showTemperature();
    		System.out.println("*********");
    	}
    	
    	public void setState(TemperatureState state) {
    		this.state = state;
    	}
    }
    
    

    TemperatureState.java

    public interface TemperatureState { // 抽象状态
    	public void showTemperature();
    }
    
    

    LowState.java

    public class LowState implements TemperatureState{ // 具体状态
    	double n = 0;
    	public LowState(double n) {
    		if(n<=0) {
    			this.n=n;
    		}
    	}
    	@Override
    	public void showTemperature() {
    		System.out.println("现在的温度是"+n+"属于低温度");
    	}
    }
    
    

    MiddleState.java

    public class MiddleState implements TemperatureState{ // 具体状态
    	double n = 15;
    	public MiddleState(double n) {
    		if(n>0&&n<26) {
    			this.n=n;
    		}
    	}
    	
    	@Override
    	public void showTemperature() {
    		System.out.println("现在的温度是"+n+"属于低温度");
    	}
    }
    
    

    HeightState.java

    public class HeightState implements TemperatureState{ // 具体状态
    	double n = 15;
    	public HeightState(double n) {
    		if(n>=39) {
    			this.n=n;
    		}
    	}
    	
    	@Override
    	public void showTemperature() {
    		System.out.println("现在的温度是"+n+"属于低温度");
    	}
    }
    
    

    Application4.java

    public class Application4 {
    	public static void main(String[] args) {
    		Thermometer thermometer = new Thermometer();
    		thermometer.setState(new LowState(0));
    		thermometer.showMessage();
    		
    		thermometer.setState(new MiddleState(15.0));
    		thermometer.showMessage();
    		
    		thermometer.setState(new HeightState(40.0));
    		thermometer.showMessage();
    	}
    }
    
    

    运行结果:
    在这里插入图片描述
    结果将所有的状态变化的行为都展示了出来。

    “状态切换”状态模式案例

    Activity.java

    public class Activity { // 环境, 这个例子属于 "状态切换" ,对应到课本上是p205页, 不是普通的状态模式
    	/**
    	 * 与普通的状态模式相比,这个 "状态切换" 就是把状态切换的操作放在了程序内部实现,不用显示的展现给用户实现;
    	 * 也就是说普通的状态模式会把切换状态的操作的过程和结果都展现出来给用户,这样是不符合生活实际的,体验感会及其差劲。
    	 *  
    	 * */
    	State state = null; // 活动当前状态, 是可以变化的
    	int count = 0; // 奖品数量
    	
    	// 四个属性表示四种状态
    	State noRaffleState = new NoRaffleState(this);
    	State canRaffleState = new CanRaffleState(this);
    	State dispenseOutState = new DispenseOutState(this);
    	State dispenseState = new DispenseState(this);
    	
    	// 初始化当前状态
    	public Activity(int count) {
    		this.state = getNoRaffleState(); // 初始化的状态是 不能抽奖状态
    		this.count = count;
    	}
    	
    	// 扣分(执行每个状态的扣分政策)
    	public void deduceMoney() {
    		state.deduceMoney();
    	}
    	
    	// 抽奖
    	public void raffle() {
    		if(state.raffle()) { // 满足条件就是抽奖成功
    			state.dispensePrize(); // 领取奖品
    		}
    	}
    	
    	public State getState() {
    		return state;
    	}
    	
    	public void setState(State state) {
    		this.state = state;
    	}
    	
    	public void setCount(int count) {
    		this.count = count;
    	}
    	
    	public int getCount() {
    		int curCount = count;
    		count--; // 每领取一次奖品, 奖品数量减少一个
    		return curCount;
    	}
    
    	public State getNoRaffleState() {
    		return noRaffleState;
    	}
    
    	public void setNoRaffleState(State noRaffleState) {
    		this.noRaffleState = noRaffleState;
    	}
    
    	public State getCanRaffleState() {
    		return canRaffleState;
    	}
    
    	public void setCanRaffleState(State canRaffleState) {
    		this.canRaffleState = canRaffleState;
    	}
    
    	public State getDispenseOutState() {
    		return dispenseOutState;
    	}
    
    	public void setDispenseOutState(State dispenseOutState) {
    		this.dispenseOutState = dispenseOutState;
    	}
    
    	public State getDispenseState() {
    		return dispenseState;
    	}
    
    	public void setDispenseState(State dispenseState) {
    		this.dispenseState = dispenseState;
    	}
    }
    
    

    State.java

    public interface State { // 抽象状态
    	public void deduceMoney(); // 扣除50积分 
    	public boolean raffle(); // 是否抽中奖品
    	public void dispensePrize(); // 发放奖品
    }
    
    

    NoRaffleState.java

    public class NoRaffleState implements State{ // 具体状态(不能抽奖状态), 当前状态可以扣除积分, 扣除后将状态设置为可以抽奖状态, 也就是当前状态不可以抽奖
    	//状态和行为是一一对应的,状态之间可以相互转换
    	Activity activity;
    	
    	public NoRaffleState(Activity activity) {
    		this.activity=activity;
    	}
    	
    	@Override
    	public void deduceMoney() {
    		System.out.println("扣除50积分成功,可以抽奖了");
    		activity.setState(activity.getCanRaffleState());
    	}
    
    	@Override
    	public boolean raffle() {
    		System.out.println("扣除积分之后才可以抽奖哦");
    		return false;
    	}
    
    	@Override
    	public void dispensePrize() {
    		System.out.println("不能发放奖品");
    	}
    }
    
    

    CanRaffleState.java

    public class CanRaffleState implements State{ // 具体状态(可以抽奖状态), 当前状态不可以扣分
    	Activity activity;
    	
    	public CanRaffleState(Activity activity) {
    		this.activity=activity;
    	}
    	
    	@Override
    	public void deduceMoney() {
    		System.out.println("以及扣除过积分了");
    	}
    
    	@Override
    	public boolean raffle() {
    		System.out.println("正在抽奖,请稍等");
    		Random random = new Random();
    		int num = random.nextInt(11); // nextInt(int index)  返回伪随机的,均匀分布的, int值介于0(含)和指定值(不包括),从该随机数生成器的序列绘制
    		//10%中奖机会
    		if(num==0) {
    			activity.setState(activity.getDispenseState());
    			return true;
    		}else { // 90%未中奖机会
    			System.out.println("很遗憾没有抽中奖品");
    			activity.setState(activity.getNoRaffleState()); // 改变状态为不能抽奖
    			return false;
    		}
    	}
    
    	@Override
    	public void dispensePrize() {
    		System.out.println("未中奖, 不能发放奖品");
    	}
    }
    
    

    DispenseState.java

    public class DispenseState implements State{ // 具体状态(发放奖品的状态)
    	Activity activity;
    	
    	public DispenseState(Activity activity) {
    		this.activity=activity;
    	}
    	
    	@Override
    	public void deduceMoney() {
    		System.out.println("不能扣除积分");
    	}
    
    	@Override
    	public boolean raffle() {
    		System.out.println("不能抽奖");
    		return false;
    	}
    
    	@Override
    	public void dispensePrize() {
    		if(activity.getCount()>0) {
    			System.out.println("恭喜中奖了");
    			activity.setState(activity.getNoRaffleState()); // 改变状态为不能抽奖
    		}else {
    			System.out.println("奖品发放完了");
    //			activity.setState(activity.getDispenseOutState()); // 改变状态为奖品发送完毕, 后面我们不能抽奖了
    			System.exit(0); // 上一句代码可以替换为此,如果是这种方式,那么当没有奖品时就会直接退出系统不会执行之后没有意义(没有奖品)的抽奖活动
    		}
    	}
    }
    
    

    DispenseOutState.java

    public class DispenseOutState implements State{ // 具体状态(奖品发放完毕状态), 此后抽奖活动结束了
    	Activity activity;
    	
    	public DispenseOutState(Activity activity) {
    		this.activity=activity;
    	}
    	
    	// 这个状态里面没有在对 State 进行任何的改变,所以一旦变为此状态就不会再变成其它状态,所以当奖品发放完时本就是本次抽奖活动结束,也就是此状态
    	@Override
    	public void deduceMoney() {
    		System.out.println("奖品发送完了, 请下次再参加");
    	}
    
    	@Override
    	public boolean raffle() {
    		System.out.println("奖品发送完了, 请下次再参加"); 
    		return false;
    	}
    
    	@Override
    	public void dispensePrize() {
    		System.out.println("奖品发送完了, 请下次再参加");
    	}
    }
    
    

    Application2.java

    public class Application2 {
    	public static void main(String[] args) {
    		Activity activity = new Activity(1); // 创建活动对象,奖品池有一个奖品
    		
    		//连续抽奖300次
    		for(int i=0;i<30;i++) {
    			System.out.println("--------第"+(i+1)+"次抽奖--------");
    			//参将抽奖, 第一步点击扣除积分
    			activity.deduceMoney();
    			//第二步抽奖
    			activity.raffle();
    		}
    	}
    }
    
    

    运行结果:
    在这里插入图片描述

    “状态切换” 与 “普通” 的状态模式相比,“切换” 就是把 “切换” 放在了类的内部,不用用户显示的实现。

    状态切换解释说明:环境实例在某种状态下执行一个方法后,可能导致该实例的状态发生变化。程序通过使用状态模式可方便地将环境实例从一个状态切换为另一个状态。当一个环境实例有确定的若干个状态时,可以由环境实例本身负责状态的切换,该环境实例可以含有所有状态的引用,并提供设置改变状态的方法,比如setState(State state)方法。

    状态模式优点:
    • 代码有很强的可读性。
    • 方便维护(删除容易产生问题的if-else语句)。
    • 使用一个类封装对象的一种状态,很容易动态的增加新的状态。
    • 在状态模式下。环境(context)中不必出现大量的条件判断语句。环境(context)实例所呈现的状态变得更加清晰,容易理解。
    • 可以让用户程序很方便地切换环境(context)实例的状态
    • 不会让环境(context)的实例中出现内部状态不一致的情况。
    • 当状态对象没有实例变量时,环境(context)的各个实例可以共享一个状态对象。
    适合场景:
    • 一个对象的行为依赖于它的状态,并且它必须在运行时根据状态改变它的行为。
    • 需要编写大量的条件分支语句来决定一个操作的行为,而且这些条件恰好表示对象的一种状态。
    展开全文
  • 最近看了刘伟老师的设计模式史上最全设计模式导学目录(完整版)_刘伟技术博客-CSDN博客学习了里面的状态模式,做一下后面的练习题。处理对象的多种状态及其相互转换——状态模式(六)_刘伟技术博客-CSDN博客 ...

    最近看了刘伟老师的设计模式史上最全设计模式导学目录(完整版)_刘伟技术博客-CSDN博客学习了里面的状态模式,做一下后面的练习题。处理对象的多种状态及其相互转换——状态模式(六)_刘伟技术博客-CSDN博客

    练习

           Sunny软件公司欲开发一款纸牌游戏软件,在该游戏软件中用户角色具有入门级(Primary)、熟练级(Secondary)、高手级(Professional)和骨灰级(Final)四种等级,角色的等级与其积分相对应,游戏胜利将增加积分,失败则扣除积分。入门级具有最基本的游戏功能play() ,熟练级增加了游戏胜利积分加倍功能doubleScore(),高手级在熟练级基础上再增加换牌功能changeCards(),骨灰级在高手级基础上再增加偷看他人的牌功能peekCards()。

           试使用状态模式来设计该系统。

     首先说一下什么是状态模式:

    状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。

     然后分析问题,首先有用户对象,用户可以有多个等级,不同等级有不同的功能,用户等级是根据用户积分来确定的,并且下一个等级是在上一个等级基础上增加一定的功能,。 这里针对不同的等级还可以使用装饰模式来实现。这里来说一下装饰模式的概述

    装饰模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。

    扩展系统功能——装饰模式(二)_刘伟技术博客-CSDN博客

    我们先定义状态接口,状态接口有三个方法,玩游戏方法play, 加分方法addScore,减分方法reduceScore:

    package com.pattern.state.practice;
    
    public interface CardState {
    
        /**
         * 玩游戏,赢了加分,输了减分
         * @param winningProbability  胜率,
         * @return 结果 true 赢,false 输,
         */
        boolean play(Double winningProbability);
    
        /**
         * 加分
         * @param cardGame
         * @param score
         */
        void addScore(PlayerGame cardGame, double score);
    
        /**
         * 减分
         * @param cardGame
         * @param score
         */
        void reduceScore(PlayerGame cardGame, double score);
    }
    

    然后创建用户对象:

    package com.pattern.state.practice;
    
    public class PlayerGame {
        private String name;//姓名,
        private Double score;//积分。
        private CardState currencyState;//当前状态。
        private CardState primaryState, secondaryState, professionalState, finalState;//入门级,熟练级,高手级。  小于100入门级,100到500熟练级,500到1000高手级, 大于1000骨灰级
        private static double winningProbability = 0.5; //赢的概率
    
        public PlayerGame(String name, double score) {
            this.name = name;
            System.out.println("玩家" + name + "准备开始!");
            primaryState = new PrimaryState();
            secondaryState = new SecondaryState();
            professionalState = new ProfessionalState();
            finalState = new FinalState();
            this.addScore(score);
        }
    
        /**
         * 玩游戏,赢了加分,输了减分
         * @param amount
         */
        public void play(double amount){
            boolean result = currencyState.play(winningProbability);
            if(result){
                //赢了加分
                System.out.println(name + "赢了!");
               currencyState.addScore(this, amount);
            }else {
                //输了减分
                System.out.println(name + "输了!");
                currencyState.reduceScore(this, amount);
            }
        }
    
        public void addScore(Double addScore){
            if(score == null){
                score = addScore;
            }else{
                score += addScore;
            }
            //设置状态
            setState();
            System.out.println("当前分数为:" + score + " 当前级别为:" + currencyState.getClass().getSimpleName());
        }
    
        private void setState(){
            if(score < 100){
                currencyState = primaryState;
            }else if(score >= 100 && score < 500){
                currencyState = secondaryState;
            }else if(score >= 500 && score < 1000){
                currencyState = professionalState;
            }else{
                currencyState = finalState;
            }
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public CardState getCurrencyState() {
            return currencyState;
        }
    
        public void setCurrencyState(CardState currencyState) {
            this.currencyState = currencyState;
        }
    
    }

    然后创建状态类,入门级,熟练级,高手级,骨灰级,状态之间从低到高依次继承上一级。类图表示为:

     入门级:

    package com.pattern.state.practice;
    
    
    /**
     * 入门级
     */
    public class PrimaryState implements CardState{
        /**
         * 这里用随机数模拟输赢, 随机数小于胜率则赢。
         * @param winningProbability  胜率,
         * @return
         */
        @Override
        public boolean play(Double winningProbability) {
            double random =  Math.random();
            if (random <= winningProbability){
                return true;
            }
            return false;
        }
    
        @Override
        public void addScore(PlayerGame cardGame, double score) {
            cardGame.addScore(score);
        }
    
        @Override
        public void reduceScore(PlayerGame cardGame, double score) {
            cardGame.addScore(-score);
        }
    }
    

     熟练级:

    package com.pattern.state.practice;
    
    /**
     * 熟练级,特有功能赢了积分加倍。
     * 重新addScore方法,加倍积分
     */
    public class SecondaryState extends PrimaryState{
        /**
         * 启用积分加倍功能
         * @param cardGame
         * @param score
         */
        @Override
        public void addScore(PlayerGame cardGame, double score) {
            score = doubleScore(score);
            System.out.println("启用积分加倍功能!加倍积分:" + score);
            super.addScore(cardGame, score);
        }
    
        /**
         * 积分加倍功能
         * @param score
         * @return
         */
        private double doubleScore(double score){
            return score * 2;
        }
    }
    

    高手级:

    package com.pattern.state.practice;
    
    /**
     * 高手级,增加换牌功能。 增加换牌功能后胜率会提升
     */
    public class ProfessionalState extends SecondaryState{
    
    
        /**
         * 这里用装饰模式实现各种技能。
         * 这里用随机数模拟输赢, 随机数小于胜率则赢。
         * 计算之前先使用换牌功能
         * @param winningProbability 胜率,
         * @return
         */
        @Override
        public boolean play(Double winningProbability) {
            winningProbability = changeCards(winningProbability);
            return super.play(winningProbability);
        }
    
        /**
         * 增加换牌功能,胜率增加, 增加幅度控制在0到0.1之间
         * @param winningProbability
         * @return
         */
        private double changeCards(double winningProbability){
            double random =  Math.random();
            winningProbability = winningProbability + random/10;
            System.out.println("使用换牌功能,胜率增加!" + winningProbability);
            return winningProbability;
        }
    
    }
    

    骨灰级:

    package com.pattern.state.practice;
    
    /**
     * 骨灰级,增加看牌功能
     */
    public class FinalState extends ProfessionalState{
        /**
         * 这里用随机数模拟输赢, 随机数小于胜率则赢。
         * 计算之前先使用换牌功能
         *
         * @param winningProbability 胜率,
         * @return
         */
        @Override
        public boolean play(Double winningProbability) {
            winningProbability = peekCards(winningProbability);
            return super.play(winningProbability);
        }
    
        /**
         * 看牌功能, 胜率增加  增加范围是 0 到 0.2
         * @param winningProbability
         * @return
         */
        private double peekCards(double winningProbability){
            double random =  Math.random();
            winningProbability = winningProbability + random/5;
            System.out.println("使用看牌功能,胜率增加!" + winningProbability);
            return winningProbability;
        }
    }
    

    然后测试一下:

    package com.pattern.state.practice;
    
    public class Client {
        public static void main(String[] args) {
            PlayerGame cardGame = new PlayerGame("赌神", 500);
            for (int i = 0; i < 100; i++) {
                cardGame.play(100);
            }
        }
    }
    

    运行结果为:

    玩家赌神准备开始!
    当前分数为:500.0 当前级别为:ProfessionalState
    使用换牌功能,胜率增加!0.5916589286277115
    赌神输了!
    当前分数为:400.0 当前级别为:SecondaryState
    赌神输了!
    当前分数为:300.0 当前级别为:SecondaryState
    赌神赢了!
    启用积分加倍功能!加倍积分:200.0
    当前分数为:500.0 当前级别为:ProfessionalState
    使用换牌功能,胜率增加!0.555551350633584
    赌神输了!
    当前分数为:400.0 当前级别为:SecondaryState
    赌神赢了!
    启用积分加倍功能!加倍积分:200.0
    当前分数为:600.0 当前级别为:ProfessionalState
    使用换牌功能,胜率增加!0.5450863977166052
    赌神赢了!
    启用积分加倍功能!加倍积分:200.0
    当前分数为:800.0 当前级别为:ProfessionalState
    使用换牌功能,胜率增加!0.5449084037248595
    赌神赢了!
    启用积分加倍功能!加倍积分:200.0
    当前分数为:1000.0 当前级别为:FinalState
    使用看牌功能,胜率增加!0.5324777583421992
    使用换牌功能,胜率增加!0.6043353386294867
    赌神输了!

     思考:实际游戏中,游戏会有多种多样的,玩家也是不同的。如果玩家玩其他游戏,这个模式就不能用了。这里在针对PlayerGame把玩家,和游戏拆分出来,用桥接模式来完成。

    桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。

     这里加一个刘伟老师的桥接模式入口:

    处理多维度变化——桥接模式(一)_刘伟技术博客-CSDN博客

     这样我们把玩家Player,游戏 Game,状态CardState都抽象成接口。

    实例如下:玩家

    package com.pattern.state.practiceup.abs;
    //玩家
    public interface Player {
        void play(double amount);
        Double getScore();
        void setScore(Double score);
        String getName();
        void setName(String name);
        Game getGame();
        void setGame(Game game);
        CardState getCurrencyState();
        void setCurrencyState(CardState currencyState);
    }
    

    游戏:

    package com.pattern.state.practiceup.abs;
    
    /**
     * 游戏,
     */
    public interface Game {
        /**
         * 玩游戏
         * @param amount
         * @param player
         */
        void play(double amount, Player player);
    
        /**
         * 加分数
         * @param addScore
         * @param player
         */
        void addScore(Double addScore, Player player);
    }
    

    状态:

    package com.pattern.state.practiceup.abs;
    
    public interface CardState {
    
        /**
         * 玩游戏,赢了加分,输了减分
         * @param winningProbability  胜率,
         * @return 结果 true 赢,false 输,
         */
        boolean play(Double winningProbability);
    
        /**
         * 加分
         * @param cardGame
         * @param player
         * @param score
         */
        void addScore(Game cardGame, Player player, double score);
    
        /**
         * 减分
         * @param cardGame
         * @param player
         * @param score
         */
        void reduceScore(Game cardGame,Player player, double score);
    }
    

    然后针对接口做实现,这样就可以有不同的玩家,玩不同的游戏。

    //斗地主游戏
    public class CardGame implements Game {
        private CardState primaryState, secondaryState, professionalState, finalState;//入门级,熟练级,高手级。  小于100入门级,100到500熟练级,500到1000高手级, 大于1000骨灰级
        private static double winningProbability = 0.5; //赢的概率
    
        public CardGame() {
            primaryState = new PrimaryState();
            secondaryState = new SecondaryState();
            professionalState = new ProfessionalState();
            finalState = new FinalState();
        }
    
        /**
         * 玩游戏,赢了加分,输了减分
         * @param amount
         * @param player
         */
        @Override
        public void play(double amount, Player player){
            CardState currencyState = player.getCurrencyState();
            boolean result = currencyState.play(winningProbability);
            if(result){
                //赢了加分
                System.out.println(player.getName() + "斗地主赢了!");
                currencyState.addScore(this, player, amount);
            }else {
                //输了减分
                System.out.println(player.getName() + "斗地主输了!");
                currencyState.reduceScore(this, player, amount);
            }
        }
    
        @Override
        public void addScore(Double addScore, Player player){
            Double score = player.getScore();
            if(score == null){
                score = addScore;
            }else{
                score += addScore;
            }
            CardState currencyState;
            if(score < 100){
                currencyState = primaryState;
            }else if(score >= 100 && score < 500){
                currencyState = secondaryState;
            }else if(score >= 500 && score < 1000){
                currencyState = professionalState;
            }else{
                currencyState = finalState;
            }
            player.setCurrencyState(currencyState);
            player.setScore(score);
            System.out.println(player.getName() + "当前分数为:" + score + " 当前级别为:" + currencyState.getClass().getSimpleName());
        }
    
    }

    玩家:

    package com.pattern.state.practiceup;
    
    import com.pattern.state.practiceup.abs.CardState;
    import com.pattern.state.practiceup.abs.Game;
    import com.pattern.state.practiceup.abs.Player;
    
    public class PlayerGame implements Player {
        private String name;//姓名,
        private Double score;//积分。
        private CardState currencyState;//当前状态。
        private Game game;  //游戏类型。 纸牌,麻将,骨牌,
        public CardState getCurrencyState() {
            return currencyState;
        }
    
        public void setCurrencyState(CardState currencyState) {
            this.currencyState = currencyState;
        }
    
        public PlayerGame(String name, double score, Game game) {
            this.name = name;
            this.game = game;
            game.addScore(score, this);
            System.out.println("玩家" + name + "准备开始!");
        }
        @Override
        public void play(double amount){
            game.play(amount,this);
        }
        @Override
        public Double getScore() {
            return score;
        }
        @Override
        public void setScore(Double score) {
            this.score = score;
        }
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public Game getGame() {
            return game;
        }
        @Override
        public void setGame(Game game) {
            this.game = game;
        }
    }
    

    状态:

    /**
     * 入门级
     */
    public class PrimaryState implements CardState {
        /**
         * 这里用随机数模拟输赢, 随机数小于胜率则赢。
         * @param winningProbability  胜率,
         * @return
         */
        @Override
        public boolean play(Double winningProbability) {
            double random =  Math.random();
            if (random <= winningProbability){
                return true;
            }
            return false;
        }
    
        @Override
        public void addScore(Game cardGame, Player player, double score) {
            cardGame.addScore(score, player);
        }
    
        @Override
        public void reduceScore(Game cardGame, Player player, double score) {
            cardGame.addScore(-score, player);
        }
    }
    
    /**
     * 熟练级,特有功能赢了积分加倍。
     * 重新addScore方法,加倍积分
     */
    public class SecondaryState extends PrimaryState {
        /**
         * 启用积分加倍功能
         * @param cardGame
         * @param player
         * @param score
         */
        @Override
        public void addScore(Game cardGame, Player player, double score) {
            score = doubleScore(score);
            System.out.println("启用积分加倍功能!加倍积分:" + score);
            super.addScore(cardGame, player, score);
        }
    
        /**
         * 积分加倍功能
         * @param score
         * @return
         */
        private double doubleScore(double score){
            return score * 2;
        }
    }
    
    /**
     * 高手级,增加换牌功能。 增加换牌功能后胜率会提升
     */
    public class ProfessionalState extends SecondaryState {
    
    
        /**
         * 这里用装饰模式实现各种技能。
         * 这里用随机数模拟输赢, 随机数小于胜率则赢。
         * 计算之前先使用换牌功能
         * @param winningProbability 胜率,
         * @return
         */
        @Override
        public boolean play(Double winningProbability) {
            winningProbability = changeCards(winningProbability);
            return super.play(winningProbability);
        }
    
        /**
         * 增加换牌功能,胜率增加, 增加幅度控制在0到0.1之间
         * @param winningProbability
         * @return
         */
        private double changeCards(double winningProbability){
            double random =  Math.random();
            winningProbability = winningProbability + random/10;
            System.out.println("使用换牌功能,胜率增加!" + winningProbability);
            return winningProbability;
        }
    
    }
    
    /**
     * 骨灰级,增加看牌功能
     */
    public class FinalState extends ProfessionalState {
        /**
         * 这里用随机数模拟输赢, 随机数小于胜率则赢。
         * 计算之前先使用换牌功能
         *
         * @param winningProbability 胜率,
         * @return
         */
        @Override
        public boolean play(Double winningProbability) {
            winningProbability = peekCards(winningProbability);
            return super.play(winningProbability);
        }
    
        /**
         * 看牌功能, 胜率增加  增加范围是 0 到 0.2
         * @param winningProbability
         * @return
         */
        private double peekCards(double winningProbability){
            double random =  Math.random();
            winningProbability = winningProbability + random/5;
            System.out.println("使用看牌功能,胜率增加!" + winningProbability);
            return winningProbability;
        }
    }
    
    

    还可以增加一个打麻将游戏:

    public class MahjongGame implements Game {
        private CardState primaryState, secondaryState, professionalState, finalState;//入门级,熟练级,高手级。  小于100入门级,100到500熟练级,500到1000高手级, 大于1000骨灰级
        private static double winningProbability = 0.5; //赢的概率
    
        public MahjongGame() {
            primaryState = new PrimaryState();
            secondaryState = new SecondaryState();
            professionalState = new ProfessionalState();
            finalState = new FinalState();
        }
    
        /**
         * 玩游戏,赢了加分,输了减分
         * @param amount
         * @param player
         */
        @Override
        public void play(double amount, Player player){
            CardState currencyState = player.getCurrencyState();
            boolean result = currencyState.play(winningProbability);
            if(result){
                //赢了加分
                System.out.println(player.getName() + "打麻将赢了!");
                currencyState.addScore(this, player, amount);
            }else {
                //输了减分
                System.out.println(player.getName() + "打麻将输了!");
                currencyState.reduceScore(this, player, amount);
            }
        }
    
        @Override
        public void addScore(Double addScore, Player player){
            Double score = player.getScore();
            if(score == null){
                score = addScore;
            }else{
                score += addScore;
            }
            CardState currencyState;
            if(score < 100){
                currencyState = primaryState;
            }else if(score >= 100 && score < 500){
                currencyState = secondaryState;
            }else if(score >= 500 && score < 1000){
                currencyState = professionalState;
            }else{
                currencyState = finalState;
            }
            player.setCurrencyState(currencyState);
            player.setScore(score);
            System.out.println(player.getName() + "当前分数为:" + score + " 当前级别为:" + currencyState.getClass().getSimpleName());
        }
    
    }
    

    测试一下:

    package com.pattern.state.practiceup;
    
    import com.pattern.state.practiceup.abs.Game;
    
    public class Client {
        public static void main(String[] args) {
            //Game game = new CardGame();
            Game game = new MahjongGame();
            PlayerGame cardGame = new PlayerGame("赌神", 500, game);
            for (int i = 0; i < 100; i++) {
                cardGame.play(100);
            }
        }
    }
    

    总结:设计模式就是把事务里面固定的东西拿出来,忽略细节,好的设计会让程序更优雅。

    再思考一下,玩游戏过程中有可能会输光所有的积分可以用备忘录模式在输光之后返回上一次的状态重新玩。

    备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对象行为型模式,其别名为Token。

     我们创建一个备忘录对象GameMemento:

    package com.pattern.state.practiceup;
    import com.pattern.state.practiceup.abs.CardState;
    import com.pattern.state.practiceup.abs.Player;
    /**
     * 游戏备忘录
     */
    public class GameMemento {
        private Double score;//积分。
        private CardState currencyState;//当前状态。
        public GameMemento(Player player) {
            this.score = player.getScore();
            this.currencyState = player.getCurrencyState();
        }
        public Double getScore() {
            return score;
        }
        public void setScore(Double score) {
            this.score = score;
        }
        public CardState getCurrencyState() {
            return currencyState;
        }
        public void setCurrencyState(CardState currencyState) {
            this.currencyState = currencyState;
        }
    }

    再创建一个备忘录责任人对象Caretaker:

    package com.pattern.state.practiceup;
    /**
     * 备忘录责任人
     */
    public class Caretaker {
        private GameMemento memento;
        public GameMemento getMemento() {
            return memento;
        }
        public void setMemento(GameMemento memento) {
            this.memento = memento;
        }
    }
    

    由Player玩家作为原发器, 在Player里面添加一个创建备忘录的方法createMemento();和一个恢复方法restorMemento(GameMemento memento);

    package com.pattern.state.practiceup.abs;
    
    import com.pattern.state.practiceup.GameMemento;
    
    public interface Player {
        void play(double amount);
        Double getScore();
        void setScore(Double score);
        String getName();
        void setName(String name);
        Game getGame();
        void setGame(Game game);
        CardState getCurrencyState();
        void setCurrencyState(CardState currencyState);
        GameMemento createMemento();
        void restorMemento(GameMemento memento);
    
    }

     再由子类实现这两个方法

    package com.pattern.state.practiceup;
    
    import com.pattern.state.practiceup.abs.CardState;
    import com.pattern.state.practiceup.abs.Game;
    import com.pattern.state.practiceup.abs.Player;
    
    public class PlayerGame implements Player {
        private String name;//姓名,
        private Double score;//积分。
        private CardState currencyState;//当前状态。
        private Game game;  //游戏类型。 纸牌,麻将,骨牌,
        //这里也可以让玩家持有 备忘录责任人
        //private Caretaker caretaker = new Caretaker();
        public CardState getCurrencyState() {
            return currencyState;
        }
    
        public void setCurrencyState(CardState currencyState) {
            this.currencyState = currencyState;
        }
    
        @Override
        public GameMemento createMemento() {
            return new GameMemento(this);
        }
    
        /*@Override
        public void restorMemento() {
            GameMemento memento = caretaker.getMemento();
            this.score = memento.getScore();
            this.currencyState = memento.getCurrencyState();
        } */
        @Override
        public void restorMemento(GameMemento memento) {
            this.score = memento.getScore();
            this.currencyState = memento.getCurrencyState();
        }
        public PlayerGame(String name, double score, Game game) {
            this.name = name;
            this.game = game;
            game.addScore(score, this);
            System.out.println("玩家" + name + "准备开始!");
        }
        @Override
        public void play(double amount){
            //caretaker.setMemento(createMemento());
            game.play(amount,this);
        }
        @Override
        public Double getScore() {
            return score;
        }
        @Override
        public void setScore(Double score) {
            this.score = score;
        }
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public Game getGame() {
            return game;
        }
        @Override
        public void setGame(Game game) {
            this.game = game;
        }
    }
    
    

    然后测试一下,为了模拟输光的场景,这里吧游戏的获胜概率给调低。MahjongGame.winningProbability=0.1;

    package com.pattern.state.practiceup;
    
    import com.pattern.state.practiceup.abs.Game;
    
    import java.util.Scanner;
    
    public class Client {
        public static void main(String[] args) {
            //Game game = new CardGame();
            Game game = new MahjongGame();
            Caretaker caretaker = new Caretaker();
            PlayerGame cardGame = new PlayerGame("赌神", 500, game);
            for (int i = 0; i < 100; i++) {
                caretaker.setMemento(cardGame.createMemento());
                cardGame.play(100);
                Double score = cardGame.getScore();
                if(score < 0){
                    System.out.println("分数为负数,是否充值一块钱,返回上一次指定分数,输入Y返回,其他退出");
                    Scanner in = new Scanner(System.in);
                    String command = in.next();
                    if("Y".equalsIgnoreCase(command)){
                        //cardGame.restorMemento();
                        System.out.println("充值成功!");
                        cardGame.restorMemento(caretaker.getMemento());
                    }else{
                        System.out.println(cardGame.getName() + "已破产!游戏结束");
                        break;
                    }
                }
            }
        }
    }
    

     运行结果:

    赌神当前分数为:500.0 当前级别为:ProfessionalState
    玩家赌神准备开始!
    使用换牌功能,胜率增加!0.13414493470770883
    赌神打麻将输了!
    赌神当前分数为:400.0 当前级别为:SecondaryState
    赌神打麻将输了!
    赌神当前分数为:300.0 当前级别为:SecondaryState
    赌神打麻将输了!
    赌神当前分数为:200.0 当前级别为:SecondaryState
    赌神打麻将赢了!
    启用积分加倍功能!加倍积分:200.0
    赌神当前分数为:400.0 当前级别为:SecondaryState
    赌神打麻将输了!
    赌神当前分数为:300.0 当前级别为:SecondaryState
    赌神打麻将输了!
    赌神当前分数为:200.0 当前级别为:SecondaryState
    赌神打麻将输了!
    赌神当前分数为:100.0 当前级别为:SecondaryState
    赌神打麻将输了!
    赌神当前分数为:0.0 当前级别为:PrimaryState
    赌神打麻将输了!
    赌神当前分数为:-100.0 当前级别为:PrimaryState
    分数为负数,是否充值一块钱,返回上一次指定分数,输入Y返回,其他退出
    y
    充值成功!
    赌神打麻将输了!
    赌神当前分数为:-100.0 当前级别为:PrimaryState
    分数为负数,是否充值一块钱,返回上一次指定分数,输入Y返回,其他退出
    y
    充值成功!
    赌神打麻将输了!
    赌神当前分数为:-100.0 当前级别为:PrimaryState
    分数为负数,是否充值一块钱,返回上一次指定分数,输入Y返回,其他退出
    y
    充值成功!
    赌神打麻将输了!
    赌神当前分数为:-100.0 当前级别为:PrimaryState
    分数为负数,是否充值一块钱,返回上一次指定分数,输入Y返回,其他退出
    t
    赌神已破产!游戏结束

    这样游戏就达到了赚钱的目的。实现盈利。

     最后来一个总的类图

     

    展开全文
  • 在本讲,我们来学习一下行为型模式里面的第五个设计模式,即状态模式状态模式引入案例 在学习状态模式之前,我们先来看一个案例,通过该案例来引出状态模式。 这个案例就是通过电梯按钮来控制一个电梯的状态。一...

    在本讲,我们来学习一下行为型模式里面的第五个设计模式,即状态模式。

    状态模式引入案例

    在学习状态模式之前,我们先来看一个案例,通过该案例来引出状态模式。

    这个案例就是通过电梯按钮来控制一个电梯的状态。一个电梯有开门状态、关门状态、停止状态、运行状态等四种状态。每一种状态改变,都有可能要根据其他状态来更新处理。例如,如果电梯门现在处于运行时状态,那么就不能进行开门操作。为什么呢?你想啊,现在电梯正处于运行状态呢,然后门开了,这是不是非常危险呀!所以,当电梯处于运行状态时是不允许执行开门操作的。而如果电梯门是停止状态,那么就可以执行开门操作了。

    下面我们就来看一下对于以上案例所设计出来的类图。

    在这里插入图片描述

    从以上类图中可以看到,我们首先定义了一个ILift接口,而且它里面声明有四个常量,即OPENING_STATE、CLOSING_STATE、RUNNING_STATE、STOPPING_STATE,它们分别是来表示电梯的四种状态的,即开启状态、关闭状态、运行状态和停止状态。

    此外,ILift接口还提供了5个抽象方法,它们分别是:

    1. setState(int state):设置电梯的状态。因为我们总得记录一下当前电梯的一个状态吧!
    2. open():电梯开门的方法
    3. close():电梯关门的方法
    4. stop():电梯停止的方法
    5. run():电梯运行的方法

    注意,ILift接口就是用于提高程序扩展性的,如果后期有其他的实体也拥有电梯的四种状态,那么我们完全可以让它去实现该接口。

    然后,我们再来看一下ILift接口的子实现类,即Lift。可以看到,在该类里面定义了一个state属性,这个属性就是用来记录当前电梯状态的。除此之外,该类还重写了父接口中的所有抽象方法。

    至于那个客户端类,我们就不用过多地去关注它了。所以,整个看下来,系统设计起来还是比较简单的。接下来,我们就得编写代码来实现以上案例了。

    首先,打开咱们的maven工程,并在com.meimeixia.pattern包下新建一个子包,即state.before,也即实现以上案例的具体代码我们是放在了该包下。

    然后,创建电梯接口,这里我们就命名为了ILift。

    package com.meimeixia.pattern.state.before;
    
    /**
     * 电梯接口
     * @author liayun
     * @create 2021-09-17 10:44
     */
    public interface ILift {
    
        // 定义四个电梯状态的常量
        int OPENING_STATE = 1;
        int CLOSING_STATE = 2;
        int RUNNING_STATE = 3;
        int STOPPING_STATE = 4;
    
        // 设置电梯状态的功能
        void setState(int state);
    
        // 电梯操作功能
        void open();
    
        void close();
    
        void run();
    
        void stop();
    
    }
    

    接着,创建电梯接口的子实现类,即电梯类,这里我们就命名为了Lift。

    package com.meimeixia.pattern.state.before;
    
    /**
     * 电梯类(ILift接口的子实现类)
     * @author liayun
     * @create 2021-09-17 10:51
     */
    public class Lift implements ILift {
    
        // 声明一个记录当前电梯状态的成员变量
        private int state;
    
        @Override
        public void setState(int state) {
            this.state = state;
        }
    
        @Override
        public void open() {
            switch (state) { // 判断当前电梯的状态
                case OPENING_STATE:
                    // 如果当前电梯正处于开启状态,那么我们再去开门,这就没有任何意义了,所以这儿我们什么事都不做
                    break;
                case CLOSING_STATE:
                    // 如果当前电梯正处于关闭状态,那么我们就能开电梯门了
                    System.out.println("电梯打开了...");
                    // 设置当前电梯状态为开启状态
                    setState(OPENING_STATE);
                    break;
                case STOPPING_STATE:
                    // 如果当前电梯正处于停止状态,那么我们也是能开电梯门的
                    System.out.println("电梯打开了...");
                    // 设置当前电梯状态为开启状态
                    setState(OPENING_STATE);
                    break;
                case RUNNING_STATE:
                    // 如果当前电梯正处于运行状态,那么我们肯定是不能去开门的,因为电梯运行时是不能开门的,所以这儿我们什么事都不做
                    break;
            }
        }
    
        @Override
        public void close() {
            switch (this.state) {
                case OPENING_STATE:
                    // 如果当前电梯正处于开启状态,那么我们就能关闭电梯门了
                    System.out.println("电梯关门了...");
                    // 设置当前电梯状态为关闭状态
                    this.setState(CLOSING_STATE);
                    break;
                case CLOSING_STATE:
                    // 如果当前电梯正处于关闭状态,那么我们再去关门,这就没有任何意义了,所以这儿我们什么事都不做
                    // do nothing
                    break;
                case RUNNING_STATE:
                    // 如果当前电梯正处于运行状态,很显然,此时电梯门肯定是关着的,那么我们就不能再去关门了,所以这儿我们什么事都不做
                    // do nothing
                    break;
                case STOPPING_STATE:
                    // 如果当前电梯正处于停止状态,很显然,此时电梯门肯定也是关着的,那么我们就不能再去关门了,所以这儿我们什么事都不做
                    // do nothing
                    break;
            }
        }
    
        @Override
        public void run() {
            switch (this.state) {
                case OPENING_STATE:
                    // 如果当前电梯正处于开启状态,那么我们肯定是不能让电梯运行的,因为电梯不能开着门就走,所以这儿我们什么事都不做
                    // do nothing
                    break;
                case CLOSING_STATE:
                    // 如果当前电梯正处于关闭状态,那么我们就能让电梯运行了
                    System.out.println("电梯开始运行了...");
                    // 设置当前电梯状态为运行状态
                    this.setState(RUNNING_STATE);
                    break;
                case RUNNING_STATE:
                    // 如果当前电梯正处于运行状态,那么我们再去运行电梯,这就没有任何意义了,所以这儿我们什么事都不做
                    // do nothing
                    break;
                case STOPPING_STATE:
                    // 如果当前电梯正处于停止状态,那么我们也是可以让电梯运行的
                    System.out.println("电梯开始运行了...");
                    // 设置当前电梯状态为运行状态
                    this.setState(RUNNING_STATE);
                    break;
            }
        }
    
        @Override
        public void stop() {
            switch (this.state) {
                case OPENING_STATE:
                    // 如果当前电梯正处于开启状态,那么我们再让电梯停止下来,就没有必要了,因为开门的电梯已经是停止的了(正常情况下),所以这儿我们什么事都不做
                    // do nothing
                    break;
                case CLOSING_STATE:
                    // 如果当前电梯正处于关闭状态,那么我们就能让电梯停止下来了,因为电梯关门时才可以停止
                    System.out.println("电梯停止了...");
                    // 设置当前电梯状态为停止状态
                    this.setState(STOPPING_STATE);
                    break;
                case RUNNING_STATE:
                    // 如果当前电梯正处于运行状态,那么我们也是能让电梯停止的,因为电梯运行时本身就可以停止啊
                    System.out.println("电梯停止了...");
                    // 设置当前电梯状态为停止状态
                    this.setState(STOPPING_STATE);
                    break;
                case STOPPING_STATE:
                    // 如果当前电梯正处于停止状态,那么我们再去让电梯停止下来,这就没有任何意义了,所以这儿我们什么事都不做
                    // do nothing
                    break;
            }
        }
    
    }
    

    最后,创建客户端类用于测试。

    package com.meimeixia.pattern.state.before;
    
    /**
     * @author liayun
     * @create 2021-09-17 11:20
     */
    public class Client {
    
        public static void main(String[] args) {
            // 创建电梯对象
            Lift lift = new Lift();
    
            // 设置当前电梯的状态
            lift.setState(ILift.OPENING_STATE);
    
            // 打开
            lift.open();
            lift.close();
            lift.run();
            lift.stop();
        }
    }
    

    此时,运行以上客户端类,打印结果如下图所示,下面我就来解释一下为何会打印出这样的结果。

    在这里插入图片描述

    当前电梯正处于开启状态,于是你再去开电梯门,那就没有任何意义了,所以执行电梯的open方法去开电梯门时,你会发现并没有任何输出。但是,现在关闭电梯门是可行的,所以在执行电梯的close方法时,你就能看到相应的输出结果了,而且此时电梯的状态就变成关闭状态了。

    当电梯处于关闭状态时,你就能让电梯运行起来了,所以在执行电梯的run方法时,你就能看到相应的输出结果了,而且此时电梯的状态又变成了运行状态。

    当电梯处于运行状态时,能让电梯停止吗?当然可以,所以在执行电梯的stop方法时,你就能看到相应的输出结果了,而且此时电梯的状态又变成了停止状态。

    大家试想一下,如果将当前电梯的状态设置为运行状态,那么打印的结果又会是什么呢?

    在这里插入图片描述

    你会发现只打印了一句话,为什么会这样呢?因为当前电梯正处于运行状态,那么此时是不允许你去开电梯门的,要是你在电梯运行的过程中开门那得多危险啊!那去关电梯门,可不可以呢?大可不必啊,因为电梯在运行过程中,本身电梯门就是关闭的,你再去关电梯门,不是有点脱裤子放屁的意思吗?那去运行电梯,可不可以呢?同样的道理啊,大可不必,因为电梯本身就在运行过程中,你再去运行电梯,那就没有必要了。那去让电梯停下来呢?此时就可以了,所以在执行电梯的stop方法时,你就能看到相应的输出结果了,即电梯停止了…

    大家再想一下,我们上面设计的系统有没有什么问题啊?是不是有如下这样的问题啊!

    • 使用了大量的switch case这样的判断语句(当然了,有些人比较喜欢使用if else语句,不过效果都是一样),使程序的可阅读性变得特别差。尤其是咱们Lift类中的方法,你会发现阅读起来体验特别特别差。

    • 扩展性很差。如果新加了断电的状态,那么我们就需要修改上面的判断逻辑。

      其实,不光要修改上面的判断逻辑,我们还得在ILift接口里面定义一个表示断电状态的常量,然后再定义一个抽象的方法,接下来,在子类中还要去重写这个方法,并且对于前面已经定义好的四个方法也要进行一个修改,所以程序的扩展性是非常差的。

    问题既然出现了,那么应该如何解决呢?嘿嘿,此时,我们就要使用状态模式了。那什么是状态模式呢?下面我就会讲到。

    概述

    上面我们做了一个电梯的案例,也引出了该电梯案例所存在的问题,并提出了解决方案,也就是使用状态模式来进行一个改进。那什么是状态模式呢?接下来,我们就来看一看它的概念。

    对有状态的对象,把复杂的"判断逻辑"提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。

    大家猛然看到状态模式的概念可能会有点懵!不过没关系,下面我会向大家一句一句来解释。

    开宗明义,状态模式说的是有状态的对象,所以对于没有状态的对象,你就不能使用状态模式了。然后,状态模式说的是把复杂的"判断逻辑"提取到不同的状态对象中,对于这句话,我们该如何理解呢?试想一下我们之前的做法,是不是在每一个方法里面使用switch case或者if else语句来进行判断的啊?现在使用状态模式就不同了,我们会避免使用switch case或者if else这些判断语句,而是把它们提取到不同的状态对象中,通过面向对象的形式,把同样的逻辑给实现出来。

    最后,状态模式说的是允许状态对象在其内部状态发生改变时改变其行为,对于这句话,我们该如何理解呢?举例来说,在上述电梯案例中,如果当前电梯现正处于运行状态中,那么我们还能执行开门的操作吗?很显然,肯定是不可以的,这也正说明了当前电梯状态发生改变会改变其行为。

    以上就是我对状态模式概念的解释,如果大家还有什么不懂的,后面我会再通过一个案例来向大家进行详细的说明。

    结构

    状态模式包含以下主要角色:

    • 环境(Context)角色:也称为上下文,它定义了客户程序需要的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。

      注意,环境角色只是对外提供了一个接口,而且在它里面维护了一个当前状态,所以,具体执行操作的还是对应的当前状态对象。

    • 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为。

    • 具体状态(Concrete State)角色:实现抽象状态所对应的行为。

    上面三个角色你不通过案例来理解,相信你是理解不了的,除非你是天选之子!这里我就不妨先举个例子来说说吧!还是以上述电梯案例来说,如果当前电梯正处于运行状态,那么我们就要创建一个电梯运行状态类了,另外还得去创建它的对象,并将该对象维护在环境角色里面。

    状态模式案例

    接下来,我们便通过状态模式来改进以上电梯案例,以此希望大家对状态模式的概念以及它里面所具有的角色有一个更深入的理解。

    分析

    对上述电梯案例使用状态模式进行改进之后的类图如下所示。

    在这里插入图片描述

    接下来,我们就要分析一下以上类图中所涉及到的类,以及类和类之间的关系了。

    可以看到,最上面有一个LiftState类,它充当的就是状态模式里面的抽象状态角色。在该类里面,我们声明了一个Context类型的成员变量,且它是protected修饰的,也就意味着子类可以直接去使用它了。那Context又是啥呢?它是环境角色类,在类图的最下面大家也能看到它,等一会我们再去详细说它啊!

    另外,在LiftState类里面我们还提供了一个setContext方法,它是用来设置环境角色类对象的。除了它之外,我们还提供了四个操作电梯状态的方法,分别是open、close、stop和run等方法,而且它们都是抽象的,既然是抽象的,那就意味着要求子类必须去实现了。

    然后,我们再来看一下LiftState类的四个子类,它们都是具体状态类,分别是电梯开启状态类、电梯关闭状态类、电梯停止状态类以及电梯运行状态类。对于这四个子类而言,它们必须去重写父类中的四个抽象方法。

    最后,我们来看一下Context类,它充当的是状态模式里面的环境角色。在该类里面,我们定义了四个具体状态类对象的常量,除此之外,我们还定义了一个LiftState类型的成员变量,它是用来记录当前电梯状态的,并且为它我们也提供了对应的getter和setter方法。

    当然了,在该类里面,我们还提供了open、close、stop以及run等这些方法,那你知道这些方法主要是来干嘛的吗?

    看一下状态模式里面对环境角色的描述,它说的是将与状态相关的操作委托给当前状态对象来处理,所以,在Context类的open、close、stop以及run这些方法里面,到时候就会去调用当前状态对象里面对应的方法了。

    实现

    首先,打开咱们的maven工程,并在com.meimeixia.pattern包下新建一个子包,即state.after,也即使用状态模式对电梯案例改进的具体代码我们是放在了该包下。

    然后,创建抽象状态类,即LiftState。

    package com.meimeixia.pattern.state.after;
    
    /**
     * 抽象状态类
     * @author liayun
     * @create 2021-09-17 11:58
     */
    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();
    
    }
    

    接着,创建四个具体状态类。这里,先创建电梯开启状态类,即OpeningState。

    package com.meimeixia.pattern.state.after;
    
    /**
     * 电梯开启状态类
     * @author liayun
     * @create 2021-09-17 12:07
     */
    public class OpeningState extends LiftState {
    
        /**
         * 当前状态下要执行的方法
         *
         * 因为当前电梯本身就处于开启状态,所以open方法就是当前电梯在开启状态下要执行的方法
         */
        @Override
        public void open() {
            System.out.println("电梯开启...");
        }
    
        /**
         * 当电梯处于开启状态时,我们是可以关闭电梯门的
         */
        @Override
        public void close() {
            // 修改状态
            super.context.setLiftState(Context.CLOSING_STATE); // 记录当前电梯的状态
            // 调用当前电梯状态对象中的Context对象中的close方法。记住,此时调用的是电梯关闭状态对象中的close方法
            super.context.close();
        }
    
        /**
         * 电梯门不能开着就跑,所以这里我们什么也不做
         */
        @Override
        public void run() {
            // 什么都不做
        }
    
        /**
         * 电梯处于开启状态时,它本身就是停止的了,所以这里我们什么也不做
         */
        @Override
        public void stop() {
            // 什么都不做
        }
        
    }
    

    电梯开启状态类创建完毕之后,接下来其他的具体状态类就比较容易创建了,照葫芦画瓢呗!

    创建的电梯运行状态类,即RunningState,代码如下所示。

    package com.meimeixia.pattern.state.after;
    
    /**
     * 电梯运行状态类
     * @author liayun
     * @create 2021-09-17 12:07
     */
    public class RunningState extends LiftState {
    
        /**
         * 电梯运行的时候开电梯门?你疯了吗!电梯它不会给你开的,所以这里我们什么也不做
         */
        @Override
        public void open() {
            // do nothing
        }
    
        /**
         * 当电梯处于运行状态时,电梯门本身就是关闭的,所以这里我们什么也不做
         */
        @Override
        public void close() {
            // do nothing
        }
    
        /**
         * 当前状态下要执行的方法
         *
         * 因为当前电梯本身就处于运行状态,所以run方法就是当前电梯在运行状态下要执行的方法
         */
        @Override
        public void run() {
            System.out.println("电梯正在运行...");
        }
    
        /**
         * 这个事绝对是合理的,电梯光运行不停止,那还有谁敢坐这个电梯啊?估计只有上帝了
         */
        @Override
        public void stop() {
            super.context.setLiftState(Context.STOPPING_STATE);
            super.context.stop();
        }
    
    }
    

    创建的电梯停止状态类,即StoppingState,代码如下所示。

    package com.meimeixia.pattern.state.after;
    
    /**
     * 电梯停止状态类
     * @author liayun
     * @create 2021-09-17 12:07
     */
    public class StoppingState extends LiftState {
    
        /**
         * 当电梯处于停止状态时,我们是可以开电梯门的
         */
        @Override
        public void open() {
            // 状态修改
            super.context.setLiftState(Context.OPENING_STATE);
            /*
             * 委托给OpeningState类来执行开电梯门这个动作
             *
             * 当然了,以下代码你也可以替换为:super.context.open();
             */
            super.context.getLiftState().open();
        }
    
        /**
         * 当电梯处于停止状态时,我们也是可以关电梯门的
         */
        @Override
        public void close() {
            // 状态修改
            super.context.setLiftState(Context.CLOSING_STATE);
            /*
             * 委托给ClosingState类来执行关电梯门这个动作
             *
             * 当然了,以下代码你也可以替换为:super.context.close();
             */
            super.context.getLiftState().close();
        }
    
        /**
         * 电梯由停止状态再跑起来,正常的很
         */
        @Override
        public void run() {
            // 状态修改
            super.context.setLiftState(Context.RUNNING_STATE);
            /*
             * 委托给RunningState类来执行运行电梯这个动作
             *
             * 当然了,以下代码你也可以替换为:super.context.run();
             */
            super.context.getLiftState().run();
        }
    
        /**
         * 当前状态下要执行的方法
         *
         * 因为当前电梯本身就处于停止状态,所以stop方法就是当前电梯在停止状态下要执行的方法
         */
        @Override
        public void stop() {
            System.out.println("电梯停止了...");
        }
    
    }
    

    创建的电梯关闭状态类,即ClosingState,代码如下所示。

    package com.meimeixia.pattern.state.after;
    
    /**
     * 电梯关闭状态类
     * @author liayun
     * @create 2021-09-17 12:07
     */
    public class ClosingState extends LiftState {
    
        /**
         * 当前状态下要执行的方法
         *
         * 因为当前电梯本身就处于关闭状态,所以close方法就是当前电梯在关闭状态下要执行的方法
         */
        @Override
        public void close() {
            System.out.println("电梯门关闭...");
        }
    
        /**
         * 电梯门关了再打开,这是允许的
         */
        @Override
        public void open() {
            super.context.setLiftState(Context.OPENING_STATE);
            super.context.open();
        }
    
        /**
         * 电梯门关了就跑,这是再正常不过的了
         */
        @Override
        public void run() {
            super.context.setLiftState(Context.RUNNING_STATE);
            super.context.run();
        }
    
        /**
         * 电梯门关着,我就是不按楼层,你能怎么着我
         */
        @Override
        public void stop() {
            super.context.setLiftState(Context.STOPPING_STATE);
            super.context.stop();
        }
    
    }
    

    以上四个具体状态类创建完毕之后,接下来,我们来创建环境角色类,即Context。

    package com.meimeixia.pattern.state.after;
    
    /**
     * 环境角色类
     * @author liayun
     * @create 2021-09-17 12:02
     */
    public class Context {
    
        // 定义对应电梯状态类对象的常量
        public final static OpeningState OPENING_STATE = new OpeningState();
        public final static ClosingState CLOSING_STATE = new ClosingState();
        public final static RunningState RUNNING_STATE = new RunningState();
        public final static StoppingState STOPPING_STATE = new StoppingState();
    
        // 定义一个记录当前电梯状态的变量
        private LiftState liftState;
    
        public LiftState getLiftState() {
            return liftState;
        }
    
        // 设置当前电梯状态对象
        public void setLiftState(LiftState liftState) {
            this.liftState = liftState;
            // 设置完当前电梯状态对象之后,别忘了,我们还得设置当前电梯状态对象中的Context对象
            this.liftState.setContext(this); // 现在我们就在Context类中,所以在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();
        }
    
    }
    

    最后,我们创建一个客户端类来用于测试。

    package com.meimeixia.pattern.state.after;
    
    /**
     * @author liayun
     * @create 2021-09-17 16:25
     */
    public class Client {
        public static void main(String[] args) {
            // 创建环境角色对象,因为我们之前就已经说过,环境角色就是对外提供访问的接口
            Context context = new Context();
            // 设置当前电梯状态
            context.setLiftState(new RunningState());
    
            context.open();
            context.close();
            context.run();
            context.stop();
        }
    }
    

    此时,运行以上客户端类,打印结果如下图所示,下面我就来解释一下为何会打印出这样的结果。

    在这里插入图片描述

    当前电梯正处于运行状态,那么你就不能再去开电梯门了,要是允许你去开电梯门,那这得多危险啊!所以,当程序执行完context.open()这行代码时,你会发现压根就没有打印任何结果。

    这时我们还能去关闭电梯门吗?电梯运行时,门本身就关闭着,你再去关闭电梯门,请问有什么意义呢?所以,当程序执行完context.close()这行代码时,你同样会发现没有打印任何结果。

    然后,当程序执行完context.run()这行代码时,我们终于看到相应的输出结果了,这是因为run方法就是当前电梯在运行状态下要执行的方法。

    接着,由于电梯在运行过程中,可以停下来,所以当程序执行完context.stop()这行代码时,我们也是能看到相应的输出结果的,只不过此时当前电梯的状态已经变成了停止状态。

    至此,使用状态模式改进的电梯案例我们就算是实现了。在改进后的电梯案例中,你会发现在我们写的代码里面并没有if else或者switch case这样的语句,而且程序的扩展性也很好,因为后期如果我们想要再添加一个断电状态,那么只需要再创建一个LiftState类的子类就可以了,当然了,Context环境角色类也要进行一个修改,只不过我们修改的地方会少很多。

    状态模式的优缺点以及使用场景

    接下来,我们来看一下状态模式的优缺点以及使用场景。

    优缺点

    优点

    关于状态模式的优点,我总结出了下面两点。

    1. 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。

    2. 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。

      在未使用状态模式改进的电梯案例中,我们就大量使用到了switch case或者if else这样的语句,这就不是面向对象的思想,而使用了状态模式之后,是不是更加面向对象了啊!此外,它还允许将状态转换逻辑和状态对象合为一体,这不是一举两得吗?

    缺点

    关于状态模式的优点,我总结出了下面三点。

    1. 状态模式的使用必然会增加系统类和对象的个数。

      在未使用状态模式改进的电梯案例中,其实也就创建了一个接口和一个类,而使用了状态模式进行了改进之后,你会发现有多少个状态就要创建多少个状态类,这样,类肯定是增加了,类增加了之后,那么相应的对象的个数肯定也会增加。

    2. 状态模式的结构与实现都较为复杂,如果使用不当,那么就会导致程序结构和代码的混乱。

      看一下咱们使用状态模式改进之后的电梯案例,在抽象状态类(即LiftState)里面就聚合了Context类的对象,而在Context类里面,你会发现又聚合了LiftState类的对象,所以程序的结构还是比较复杂的,这样的话,我们在设计的时候就一定要加倍小心了。

    3. 状态模式对"开闭原则"的支持并不太好。

      你想啊,后期如果我们想要添加一个新的状态,那么我们不光要添加一个新的状态类,还要去修改Context类里面的代码,并且对于那些具体状态类的代码我们也要稍微进行一个修改,所以我们才说状态模式对开闭原则的支持并不是特别好。

    使用场景

    只要出现如下几个场景,我们就可以去考虑一下能不能使用状态模式了。

    • 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式了。

      状态模式主要体现的就是状态,只要一个对象的行为取决于它的状态(状态不一样,对象的行为也会不一样),那么这个时候你就可以考虑使用状态模式了。

    • 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。

      也就是说,如果你写的代码里面大量地运用到了switch case或者if else语句,那么这个时候你就不妨试试使用状态模式。

    展开全文
  • 行为取决于它的状态,即是说由状态决定行为,方法放在状态类中,而状态控制亦在状态类中进行,譬如一个按钮,按一次是开,按一次是关,同...State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身...

    行为取决于它的状态,即是说由状态决定行为,方法放在状态类中,而状态控制亦在状态类中进行,譬如一个按钮,按一次是开,按一次是关,同一个行为,但是由于其状态的改变,而导致不同的结果。

    一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常, 有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

    即是说以前你需要在某个行为的方法里面用if/else或者switch中写的一堆业务,现在可以转移到状态类中了,而该状态类是独立的,非常便于流程管理。譬如之前的开关,你需要在toggle()中写if/else,并且需要返回flag以便判断状态,而使用状态类,将状态分为开/关两种状态,只需要在状态类的toggle()方法中写入逻辑,将行为后的状态返回即可。

    实现:

    需要实现这个逻辑:

    0818b9ca8b590ca3270a3433284dd417.png

    0818b9ca8b590ca3270a3433284dd417.png

    那么我们就需要

    3个具体状态类(已预订,已确认,已锁定)

    以及3个行为(确认,修改,支付)

    抽象状态类

    abstract class OrderState {

    abstract void confirm(OrderContext orderContext);

    abstract void modify(OrderContext orderContext);

    abstract void pay(OrderContext orderContext);

    }

    具体状态类

    class OrderedState extends OrderState {

    @Override

    void confirm(OrderContext orderContext) {

    System.out.println("订单已确认");

    orderContext.setState(new ConfirmedState());

    }

    @Override

    void modify(OrderContext orderContext) {

    System.out.println("订单已修改");

    orderContext.setState(this);

    }

    @Override

    void pay(OrderContext orderContext) {

    System.out.println("预定状态无法完成订单!");

    }

    }

    class ConfirmedState extends OrderState {

    @Override

    void confirm(OrderContext orderContext) {

    System.out.println("订单已确认,请勿重复确认");

    }

    @Override

    void modify(OrderContext orderContext) {

    System.out.println("订单已修改,请再次确认");

    orderContext.setState(new OrderedState());

    }

    @Override

    void pay(OrderContext orderContext) {

    System.out.println("订单已支付,无法再修改");

    orderContext.setState(new LockedState());

    }

    }

    class LockedState extends OrderState {

    @Override

    void confirm(OrderContext orderContext) {

    System.out.println("订单已锁定");

    }

    @Override

    void modify(OrderContext orderContext) {

    System.out.println("订单已锁定");

    }

    @Override

    void pay(OrderContext orderContext) {

    System.out.println("订单已锁定");

    }

    }

    背景类

    class OrderContext {

    OrderState state = null;

    //新建订单设为已预定状态

    OrderContext() {

    this.state = new OrderedState();

    }

    void setState(OrderState state) {

    this.state = state;

    }

    public void confirm() {

    state.confirm(this);

    }

    public void modify() {

    state.modify(this);

    }

    public void pay() {

    state.pay(this);

    }

    }测试:

    public static void main(String[] args) {

    OrderContext orderContext = new OrderContext();

    orderContext.confirm(); //已预定状态>已确认状态

    orderContext.modify(); //已确认状态>已预定状态

    orderContext.confirm(); //已预定状态>已确认状态

    orderContext.pay(); //已确认状态>已锁定状态

    orderContext.modify(); //已锁定状态

    }

    订单已确认

    订单已修改,请再次确认

    订单已确认

    订单已支付,无法再修改

    订单已锁定

    展开全文
  • 设计模式:行为型-状态模式

    千次阅读 多人点赞 2021-04-11 17:34:19
    目录第一章 状态模式介绍第二章 状态模式实现2.1、环境类2.2、抽象状态类2.3、具体状态类2.4、测试类第三章 状态模式应用3.1、环境类3.2、抽象状态类3.3、具体状态类3.4、测试类 项目地址:...
  • 接下来我们通过这个电梯系统来学习一下状态模式。 一、电梯系统分析 电梯的状态有停止、运行、开门和关门等状态。而且每个状态还都要有特定的行为,比如在开门的状态下,电梯只能关门,而不能运行;在关门状态下...
  • 设计模式-状态模式

    千次阅读 2021-10-23 19:46:13
    今天学习了状态模式,做个总结。 本文多出摘选自《设计模式之禅》,只留作学习复习只用。 为了更好地了解学习状态模式,先认识一个小例子——电梯。 举个例子 电梯大家应该都很熟悉,日常生活用得到,电梯的日常...
  • 一次状态模式的优化

    2021-06-10 14:17:19
    状态模式就是允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。 对象的具体行为是根据它的当前状态而具体实现,是多态的。 适用性: 1、 一个对象的行为取决于它的状态,并且必须在运行...
  • 我和女朋友的这个烧烤店越做越大,已经容不下...状态之间又可以互相切换,虽然复杂,但是难不倒我天才的我,而且电梯的事情,也让我沉淀了一个设计模式《状态模式》。 一、状态模式(State)基本概念 1.1 定义 ...
  • 文章目录前言 前言 在工作时遇到了这样一个需求: 控制消毒柜: 1. 当柜门打开时,关闭消毒,并重置已消毒时间;...本文通过这样一个真实的公司需求,讲解设计模式中的状态模式,以及他的应用----状态机。 ...
  • 模式的结构和实现3.1 模式的结构3.2模式的实现 1.前言 在现实生活中,人都有高兴和伤心的时候,不同的时候有不同的行为,有状态的对象编程中高兴,伤心可以看成一种状态,传统的解决方案是:人的不同时候的行为都要...
  • 状态模式(State)一、状态模式定义二、实现范例三、使用状态模式(state)实现游戏场景的转换四、使用状态模式的优点 一、状态模式定义 状态模式(state)在GoF中的解释: 让一个对象的行为随着内部状态的改变而...
  • 设计模式行为型-状态模式

    千次阅读 2021-10-31 08:26:03
    最近学习了设计模式行为型中的状态模式,这个模式的就完全体现出“多态”这种性质了,首先是它的解释:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。 为什么说状态模式就体现出多态?...
  • 游戏开发设计模式--状态模式

    千次阅读 2021-10-30 15:30:23
    使用场景: 对象可处理成多个状态,每个状态有不同的行为方式,简单情况下可使用switch-case实现,当需求复杂到一定程度时,switch-case会使得代码集中、复杂,不宜扩展和调试,这时可使用状态模式。 实现 Context ...
  • C++23种设计模式(20)-状态模式

    万次阅读 2021-11-03 17:00:53
    状态模式:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。它有两种使用情况:(1)一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。(2)一个操作中含有庞大...
  • 一. 为什么要引入状态模式? 系统状态的变化引起实际行为的改变,因此我们需要在系统的主任务中判断他们处于哪一个状态,使用if-else if-else或者switch-case分支结构可以很好的解决。但是如果在某个每个状态在...
  • 文章目录前言状态模式UML类图使用场合代码实现总结 前言 在实际开发中,我们经常会遇到这种情况;一个对象有多种状态,在每一个状态下,都会有不同的行为。那么在代码中我们经常是这样实现的。 enum State { state1...
  • 状态模式就是一个对象的状态改变时,它的行为也会改变 使用情况: (1)、对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为。 (2)、代码中包含大量与对象状态有关的条件语句,这些...
  • 这么看结构其实还是不复杂的,而且跟状态模式类似。 那么这个代码怎么实现? 举个例子,汽车大家肯定都不陌生,愿大家早日完成汽车梦,汽车的不同档(concreteStrategy)就好比不同的策略,驾驶者选择几档则汽车按几...
  • 基于STM32HAL库编写状态模式

    千次阅读 2021-06-16 16:27:59
    概述 本篇文章介绍如何使用STM32HAL库,“以马达转动的状态示例”来说明,项目中使用的状态模式。参考该文章链接,比较懒,基本都是照搬框架。这种写法确实在项目后续新增功能时,方便不少,还是值得学习,这样的...
  • Java常见设计模式总结

    万次阅读 多人点赞 2021-09-18 17:18:54
    设计模式是一套经过反复使用的代码设计经验,目的是为了重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式于己于人于系统都是多赢的,它使得代码编写真正工程化,它是软件工程的基石,如同大厦的一块块...
  • if (@available(iOS 13.0, *)) { [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDarkContent; } else { // Fallback on earlier versions }
  • Hadoop下hdfs开关安全模式、查看安全模式状态 1.查看模式状态 $ hdfs dfsadmin -safemode get 2.离开安全模式 $ hdfs dfsadmin -safemode leave 3.进入安全模式 $ hdfs dfsadmin -safemode enter 例:如图
  • 这篇文章我们来讲解下行为型设计模式的观察者、状态、中介者模式。 二、观察者模式 当一个对象被修改时,则会自动通知依赖它的对象。对象间存在一对多关系时就可以选用这个设计模式,优点是观察者和被观察者是抽象...
  • 1.1数据库的模式: 1、普通模式(normal):用户可以正常...1、配置状态(MOUNT):不允许访问数据库对象,只能进行控制文件,参数文件维护,归档配置,数据库模式修改等操作。2、打开状态(OPEN):不能进行控制文件维护,归
  • Stop模式下,MCU的GPIO是可以保持休眠之前的状态的,且所有的寄存器在休眠状态下保持休眠前的状态不变,比如说休眠后需要某个LED控制亮着灯是可以实现的(已实验测试验证)。 1、sleep模式(Cortex-M3内核停止,外设...
  • 状态模式(State)

    千次阅读 2021-06-29 08:40:58
    什么是状态模式? 对一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。 Context:维护一个ConcreteState子类的实例,这个实例定义当前的状态;(策略模式也有) ConcreteStateA:...
  • Doze模式简介

    千次阅读 2021-02-17 23:29:34
    Doze模式是自Android 6.0开始引入的两项省电功能的其中之一,还有一个就是appstandby...如果用户未插接设备的电源,在屏幕关闭的情况下,让设备在一段时间内保持不活动状态,那么设备就会进入低电耗模式。在低电耗模式
  • vuex 状态管理模式(一)

    2021-11-09 09:48:46
    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools Vuex ...
  • 文章目录引言I 、状态栏背景颜色的适配方案1.1 使用新的API 【statusBarManager】1.2 适配特色场景:状态是有透明或者半透明的效果的场景 引言 设置状态栏背景颜色的解决方案:使用新的API 【statusBarManager】 I ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,806,998
精华内容 722,799
关键字:

状态模式

友情链接: code_nr_alg3_book2.rar