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

    千次阅读 2018-11-30 11:49:30
    状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它所属的类,属于行为型模式。 2、模式结构 环境角色(Context):定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体...

    1、概念

    状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它所属的类,属于行为型模式。
    在这里插入图片描述

    2、模式结构

    • 环境角色(Context):定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
    • 抽象状态角色(State):定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。
    • 具体状态角色(ConcreteState):每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

    3、使用场景

    • 对象的行为依赖于它的某些属性值,状态的改变将导致行为的变化
    • 在代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强

    4、优缺点

    优点:

    • 封装了转换规则
    • 枚举可能的状态,在枚举状态之前需要确定状态种类
    • 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为
    • 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块
    • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数

    缺点:

    • 增加系统类和对象的个数
    • 结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱
    • 对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码

    5、实例

    定义抽象状态角色ConnectState

    public interface ConnectState {
        void handleAction();
    }
    

    定义具体状态角色ReconnectState

    public class ReconnectState implements ConnectState {
    
        @Override
        public void handleAction() {
            // 重连逻辑
        }
    }
    

    定义具体状态角色SuccessState

    public class SuccessState implements ConnectState {
    
        @Override
        public void handleAction() {
            // 成功逻辑
        }
    }
    

    定义具体状态角色FailureState

    public class FailureState implements ConnectState {
    
        @Override
        public void handleAction() {
            // 失败逻辑
        }
    }
    

    定义环境角色Context

    public class Context {
        private ReconnectState reconnectState;
        private FailureState failureState;
        private SuccessState successState;
    
        public void reconnect() {
            if (reconnectState == null) {
                reconnectState = new ReconnectState();
            }
            reconnectState.handleAction();
        }
    
        public void failure() {
            if (failureState == null) {
                failureState = new FailureState();
            }
            failureState.handleAction();
        }
    
        public void success() {
            if (successState == null) {
                successState = new SuccessState();
            }
            successState.handleAction();
        }
    }
    
    展开全文
  • 设计模式:状态模式(State)

    千次阅读 2020-04-23 18:50:09
    状态模式的角色 1. 环境角色Context):也称上下文,定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。 2. 抽象状态角色(State):定义一个接口,用以...

    欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


    欢迎跳转到本文的原文链接:https://honeypps.com/design_pattern/state/

    允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
    这里写图片描述

    状态模式的角色

    1. 环境角色Context):也称上下文,定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
    2. 抽象状态角色(State):定义一个接口,用以封装环境对象的一个特定的状态所对应的行为。
    3. 具体状态角色(ConcreteState):每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

    案例
    以酒店订房为例,房间的状态有:空闲、预订、入住。那么空闲房间的状态可以转变为:预订、入住。已预订状态房间的状态可以转变为:入住、取消预订。已入住房间的状态可以转变为:退房
    1 状态接口State

    public interface State
    {
        public void bookRoom();
        public void unsubscribeRoom();
        public void checkInRoom();
        public void checkOutRoom();
    }
    

    2 房间类Room(环境角色)

    public class Room
    {
        private State freeTimeState;
        private State checkInState;
        private State bookedState;
    
        private State state;
    
        public Room()
        {
            freeTimeState = new FreeTimeState(this);
            checkInState = new CheckInState(this);
            bookedState = new BookedState(this);
            state = freeTimeState;
        }
    
        public void bookRoom()
        {
            state.bookRoom();
        }
        public void unsubscribeRoom()
        {
            state.unsubscribeRoom();
        }
        public void checkInRoom()
        {
            state.checkInRoom();
        }
        public void checkOutRoom()
        {
            state.checkOutRoom();
        }
    
        public String toString()
        {
            return "该房间的状态是:"+getState().getClass().getName();
        }
    
        public State getFreeTimeState()
        {
            return freeTimeState;
        }
    
        public void setFreeTimeState(State freeTimeState)
        {
            this.freeTimeState = freeTimeState;
        }
    
        public State getCheckInState()
        {
            return checkInState;
        }
    
        public void setCheckInState(State checkInState)
        {
            this.checkInState = checkInState;
        }
    
        public State getBookedState()
        {
            return bookedState;
        }
    
        public void setBookedState(State bookedState)
        {
            this.bookedState = bookedState;
        }
    
        public State getState()
        {
            return state;
        }
    
        public void setState(State state)
        {
            this.state = state;
        }
    }
    

    3 房间状态(具体状态角色)
    空闲状态

    public class FreeTimeState implements State
    {
        private Room hotelManagement;
    
        public FreeTimeState(Room hotelManagement)
        {
            this.hotelManagement = hotelManagement;
        }
        @Override
        public void bookRoom()
        {
            System.out.println("您已经预定成功了!");
            this.hotelManagement.setState(this.hotelManagement.getBookedState());
        }
    
        @Override
        public void unsubscribeRoom()
        {
        }
    
        @Override
        public void checkInRoom()
        {
            System.out.println("您已经入住了!");
            this.hotelManagement.setState(this.hotelManagement.getCheckInState());
        }
    
        @Override
        public void checkOutRoom()
        {
        }
    }
    

    入住状态

    public class CheckInState implements State
    {
        private Room hotelManagement;
    
        public CheckInState(Room hotelManagement)
        {
            this.hotelManagement = hotelManagement;
        }
        @Override
        public void bookRoom()
        {
            System.out.println("该房间已经入住了");
        }
    
        @Override
        public void unsubscribeRoom()
        {
        }
    
        @Override
        public void checkInRoom()
        {
            System.out.println("该房间已经入住了");
        }
    
        @Override
        public void checkOutRoom()
        {
            System.out.println("退房成功");
            this.hotelManagement.setState(this.hotelManagement.getFreeTimeState());
        }
    }
    

    预订状态

    public class BookedState implements State
    {
        private Room hotelManagement;
    
        public BookedState(Room hotelManagement)
        {
            this.hotelManagement = hotelManagement;
        }
    
        @Override
        public void bookRoom()
        {
            System.out.println("该房间已经预定了");
        }
    
        @Override
        public void unsubscribeRoom()
        {
            System.out.println("成功退订");
            this.hotelManagement.setState(this.hotelManagement.getFreeTimeState());
        }
    
        @Override
        public void checkInRoom()
        {
            System.out.println("入住成功");
            this.hotelManagement.setState(this.hotelManagement.getCheckInState());
        }
    
        @Override
        public void checkOutRoom()
        {
        }
    }
    

    4 测试代码

            Room[] rooms = new Room[2];
            for(int i=0;i<rooms.length;i++)
            {
                rooms[i] = new Room();
            }
    
            rooms[0].bookRoom();
            rooms[0].checkInRoom();
            rooms[0].bookRoom();
            System.out.println(rooms[0]);
            System.out.println("-------------");
    
            rooms[1].checkInRoom();
            rooms[1].bookRoom();
            rooms[1].checkOutRoom();
            rooms[1].bookRoom();
            System.out.println(rooms[1]);
    

    输出:

    您已经预定成功了!
    入住成功
    该房间已经入住了
    该房间的状态是:design.state.CheckInState
    -------------
    您已经入住了!
    该房间已经入住了
    退房成功
    您已经预定成功了!
    该房间的状态是:design.state.BookedState
    

    优缺点
    优点:

    1. 封装了转换规则。
    2. 枚举可能的状态,在枚举状态之前需要确定状态种类。
    3. 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
    4. 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
      缺点:
    5. 状态模式的使用必然会增加系统类的对象的个数
    6. 状态模式的结构与实现都较为复杂,如果使用不当讲导致程序结构和代码的混乱。
    7. 状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

    适用场景

    1. 对象的行为依赖于它的状态(属性)并且可以根据它的状态而改变它的相关行为
    2. 代码中包含大量与对象状态相关的条件语句

    JDK中的状态模式:
    java.util.Iterator
    javax.faces.lifecycle.LifeCycle#execute()


    欢迎跳转到本文的原文链接:https://honeypps.com/design_pattern/state/

    参考资料

    1. 23种设计模式
    2. 细数JDK里的设计模式
    3. 设计模式读书笔记—–状态模式

    欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


    展开全文
  • JAVA设计模式--状态模式

    万次阅读 2019-03-26 10:30:10
    一、什么是状态模式 二、状态模式的结构 三、状态模式应用举例 四、理解状态模式 五、状态模式的适用性 六、状态模式的优缺点 一、什么是状态模式 状态(State))模式,又称状态对象(Pattern of Objects for ...

    目录

    一、什么是状态模式

    二、状态模式的结构

    三、状态模式应用举例

    四、理解状态模式

    五、状态模式的适用性

    六、状态模式的优缺点


    一、什么是状态模式

    状态(State))模式,又称状态对象(Pattern of Objects for States)模式,是一种对象的行为模式。状态模式允许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。

    状态模式的本质:根据状态来分离和选择行为  

    二、状态模式的结构

    状态模式涉及的角色及其职责如下:

    环境(Context)角色:也称上下文,通常用来定义客户端感兴趣的接口,同时维护一个来具体处理当前状态的对象示例。
    抽象状态(State)角色:定义一个接口,用来封装与环境(Context)对象的一个特定的状态所对应的行为。
               具体状态(ConcreteState)角色:每一个具体状态类都实现了一个跟环境(Context)相关的状态的具体处理。

    状态模式结构示意源代码如下:

    /**
     * 抽象状态(State)角色,用来封装与环境(Context)对象的一个特定的状态所对应的行为
     */
    public interface State {
    
    	/**
    	 * 状态对应的处理
    	 * 
    	 * @param sampleParameter 示例参数
    	 */
    	public void handle(String sampleParameter);
    }
    /**
     * 具体状态(ConcreteState)角色,实现一个与Context的一个特定状态相关的行为
     */
    public class ConcreteStateA implements State {
    
    	@Override
    	public void handle(String sampleParameter) {
    		// 实现具体的处理
    
    	}
    
    }
    /**
     * 具体状态(ConcreteState)角色,实现一个与Context的一个特定状态相关的行为
     */
    public class ConcreteStateB implements State {
    
    	@Override
    	public void handle(String sampleParameter) {
    		// 实现具体的处理
    
    	}
    
    }

     

    /**
     * 环境(Context)角色
     */
    public class Context {
    
    	// 持有一个State类型的对象实例
    	private State state;
    
    	public void setState(State state) {
    		this.state = state;
    	}
    
    	public void request(String sampleParameter) {
    		// 处理操作,会转调State来处理
    		state.handle(sampleParameter);
    	}
    }

    三、状态模式应用举例

    《研磨设计模式》中给出这么一个场景:实现在线投票。
                考虑一个在线投票的应用,要实现控制同一个用户只能投一票,如果一个用户重复投票,而且投票次数超过5次,则判定为恶意刷票,要取消该用户投票的资格,当然同时也要取消他所投的票;如果一个用户的投票次数超过8次,将进入黑名单,禁止再登录和使用系统。

    以上功能我们使用状态模式来实现:
               首先需要把投票过程的各种状态定义出来,根据以上描述大致分为四种状态:正常投票、重复投票、恶意刷票、进入黑名单。

    设计好的程序结构如图所示:

    先来看看状态接口的代码实现,示例代码如下。 

    public interface VoteState {
    	/**
    	 * 处理状态对应的行为
    	 * 
    	 * @param user
    	 *            投票人
    	 * @param voteItem
    	 *            投票项
    	 * @param voteManager
    	 *            投票上下文,用来在实现状态对应的功能处理的时候, 可以回调上下文的数据
    	 */
    	public void vote(String user, String voteItem, VoteManager voteManager);
    }

    接下来看看各个状态对应的处理,示例代码如下。 

    /**
     * 正常投票状态
     */
    public class NormalVoteState implements VoteState {
    
    	@Override
    	public void vote(String user, String voteItem, VoteManager voteManager) {
    		// 正常投票,记录到投票记录中
    		voteManager.getMapVote().put(user, voteItem);
    		System.out.println("恭喜您,投票成功。");
    	}
    
    }
    /**
     * 重复投票状态
     */
    public class RepeatVoteState implements VoteState {
    	@Override
    	public void vote(String user, String voteItem, VoteManager voteManager) {
    		// 重复投票,此处仅打印一个警告作为示意
    		System.out.println("警告:请不要重复投票!");
    	}
    }
    /**
     * 恶意刷票状态
     */
    public class SpiteVoteState implements VoteState {
    	@Override
    	public void vote(String user, String voteItem, VoteManager voteManager) {
    		// 恶意投票,取消用户的投票资格,并取消投票记录
    		String str = voteManager.getMapVote().get(user);
    		if (str != null) {
    			voteManager.getMapVote().remove(user);
    		}
    		System.out.println("你有恶意刷屏行为,取消投票资格!");
    	}
    }
    /**
     * 黑名单状态
     */
    public class BlackVoteState implements VoteState {
    	@Override
    	public void vote(String user, String voteItem, VoteManager voteManager) {
    		// 记录在黑名单中,禁止登录系统
    		System.out.println("提示:您已进入投票黑名单,禁止登录和使用本系统!");
    	}
    
    }

    最后看看投票管理,相当于状态模式中的上下文,示例代码如下。 

    import java.util.HashMap;
    import java.util.Map;
    
    public class VoteManager {
    	// 持有状体处理对象实例
    	private VoteState state = null;
    	// 记录用户投票的结果,Map<String,String>对应Map<用户名称,投票的选项>
    	private Map<String, String> mapVote = new HashMap<String, String>();
    	// 记录用户投票次数,Map<String,Integer>对应Map<用户名称,投票的次数>
    	private Map<String, Integer> mapVoteCount = new HashMap<String, Integer>();
    
    	/**
    	 * 获取用户投票结果的Map
    	 */
    	public Map<String, String> getMapVote() {
    		return mapVote;
    	}
    
    	/**
    	 * 投票
    	 * 
    	 * @param user
    	 *            投票人
    	 * @param voteItem
    	 *            投票的选项
    	 */
    	public void vote(String user, String voteItem) {
    		// 1.为该用户增加投票次数
    		// 从记录中取出该用户已有的投票次数
    		Integer oldVoteCount = mapVoteCount.get(user);
    		if (oldVoteCount == null) {
    			oldVoteCount = 0;
    		}
    		oldVoteCount += 1;
    		mapVoteCount.put(user, oldVoteCount);
    		// 2.判断该用户的投票类型,就相当于判断对应的状态
    		// 到底是正常投票、重复投票、恶意投票还是上黑名单的状态
    		if (oldVoteCount == 1) {
    			state = new NormalVoteState();
    		} else if (oldVoteCount > 1 && oldVoteCount < 5) {
    			state = new RepeatVoteState();
    		} else if (oldVoteCount >= 5 && oldVoteCount < 8) {
    			state = new SpiteVoteState();
    		} else if (oldVoteCount > 8) {
    			state = new BlackVoteState();
    		}
    		// 3.然后转调状态对象来进行相应的操作
    		state.vote(user, voteItem, this);
    	}
    }
    

    写个客户端来测试一下,示例代码如下。 

    public class Client {
    
    	public static void main(String[] args) {
    		// 创建一个投票管理对象实例
    		VoteManager vm = new VoteManager();
    
    		// 通过一个循环操作来模仿用户连续投票9次的行为
    		for (int i = 0; i < 9; i++) {
    			vm.vote("u1", "A");
    		}
    	}
    
    }

    运行程序打印结果如下: 

    恭喜您,投票成功。
    警告:请不要重复投票!
    警告:请不要重复投票!
    警告:请不要重复投票!
    你有恶意刷屏行为,取消投票资格!
    你有恶意刷屏行为,取消投票资格!
    你有恶意刷屏行为,取消投票资格!
    你有恶意刷屏行为,取消投票资格!
    提示:您已进入投票黑名单,禁止登录和使用本系统!

    四、理解状态模式

    (1)状态和行为

    所谓对象的状态,通常指的就是对象实例的属性的值;而行为指的就是对象的功能,再具体点说,行为大多可以对应到方法上。

    状态模式的功能就是分离状态的行为,通过维护状态的变化,来调用不同状态对应的不同功能。也就是说,状态和行为是相关联的,它们的关系可以描述为:状态决定行为。

    由于状态是在运行期间被改变的,因此行为也会在运行期间根据状态的改变而改变,看起来,同一个对象,在不同的运行时刻,行为是不一样的,就像是类被修改了一样。

    (2)行为的平行性

    注意平行性而不是平等性。所谓平行性指的是各个状态的行为所处的层次是一样的,相互独立的、没有关联的,是根据不同的状态来决定到底走平行线的哪一条。行为是不同的,当然对应的实现也是不同的,相互之间是不可替换的,如下图所示。 

    而平等性强调的是可替换性,大家是同一行为的不同描述或实现,因此在同一个行为发生的时候,可以根据条件挑选任意一个实现来进行相应的处理,如下图所示。

    大家可能会发现状态模式的结构和策略模式的结构完全一样,但是,它们的目的、实现、本质却是完全不一样的。还有行为之间的特性也是状态模式和策略模式一个很重要的区别,状态模式的行为是平行性的,不可相互替换的;而策略模式的行为是平等性的,是可以相互替换的。

    (3)环境和状态处理对象

    在状态模式中,环境(Context)是持有状态的对象,但是环境自身并不处理跟特定的状态相关的行为,而是把处理状态的功能委托给了状态对应的状态处理类来处理。

    在具体的状态处理类中经常需要获取环境自身的数据,甚至在必要的时候会回调环境的方法,因此,通常将环境自身当作一个参数传递给具体的状态处理类。

    客户端一般只和环境交互。客户端可以用状态对象来配置一个环境,一旦配置完毕,就不再需要和状态对象打交道了。客户端通常不负责运行期间状态的维护,也不负责决定后续到底使用哪一个具体的状态处理对象。 

    五、状态模式的适用性

    在以下条件下可以考虑使用状态模式:
               • 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
               • 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。 

    六、状态模式的优缺点

    使用状态模式的优点:

    (1)简化应用逻辑控制
               状态模式使用单独的类来封装一个状态的处理,可以把负责逻辑控制的代码分散到单独的状态类中去,这样就把着眼点从执行状态提高到整个对象的状态,使得代码结构化和意图更清晰,从而简化应用的逻辑控制。
               (2)更好地分离状态和行为
               状态模式通过设置所有状态类的公共接口,把状态和状态对应的行为分离开,把所有与一个特定的状态相关的行为都放入一个对象中,使得应用程序在控制的时候,只需要关心状态的切换,而不用关心这个状态对应的真正处理。
               (3)更好的扩展性
               引入了状态处理的公共接口后,使得扩展新的状态变得非常容易,只需要新增加一个实现状态处理的公共接口的实现类,然后在进行状态维护的地方,设置状态变化到这个新的状态即可。
               (4)显式化进行状态转换
               状态模式为不同的状态引入独立的对象,使得状态的转换变得更加明确。而且状态对象可以保证上下文不会发生内部状态不一致的情况,因为上下文中只有一个变量来记录状态对象,只要为这一个变量赋值就可以了。

    使用状态模式的缺点:

    一个状态对应一个状态处理类,会使得程序引入太多的状态类,这样程序变得杂乱。 

    展开全文
  • 状态模式

    千次阅读 2018-05-30 22:49:30
      状态模式的含义是将对象的状态封装成一个独立的类,并将动作行为委托到代表当前状态的对象,行为会随着内部的状态而改变。状态模式是通过状态对象来改变动作行为,而不同的状态对象里不同的动作行为表现会不一样...

    定义:

    允许一个对象在其内部状态改变时改变它的行为,这个对象看起来就像改变了它的类一样。

      状态模式的含义是将对象的状态封装成一个独立的类,并将动作行为委托到代表当前状态的对象,行为会随着内部的状态而改变。状态模式是通过状态对象来改变动作行为,而不同的状态对象里不同的动作行为表现会不一样,这使得它看起来就像在改变它的类一样。

    设计类图:

    状态模式中的角色:

    • Context上下文环境角色,负责状态的切换,持有一个内部状态对象,代表着环境当前所处的状态。
    • State抽象状态角色, 可以是一个接口或者抽象类,定义了所有具体状态的共同接口或者是说动作行为,任何具体状态都要实现这些接口。
    • ConcreteState具体状态角色,处理来自Context的请求,每一个ConcreteState都提供了它自己对请求的实现,它要完成两个任务,一个是本状态下的行为管理,另一个是如何过渡到下一个状态。并且持有环境角色以实现状态的切换。
    public interface State {
        //行为1
        public void handle1();
        //行为2
        public void handle2();
    }
    public class ConcreteStateA implements State {
        private Context context;
    
        public ConcreteStateA(Context context) {
            this.context = context;
        }
    
        @Override
        public void handle1() {
            //当前状态下handle1行为的处理
            //...
        }
    
        @Override
        public void handle2() {
            //当前状态下handle2行为的处理
            //...
            this.context.setCurrentSate(Context.STATE_B);
        }
    }
    
    public class ConcreteStateB implements State {
        private Context context;
    
        public ConcreteStateB(Context context) {
            this.context = context;
        }
    
        @Override
        public void handle1() {
            //当前状态下handle1行为的处理
            //...
        }
    
        @Override
        public void handle2() {
            //当前状态下handle2行为的处理
            //...
            this.context.setCurrentSate(Context.STATE_A);
        }
    }
    public class Context {
        public static State STATE_A;
        public static State STATE_B;
        private State currentSate;
    
        public Context() {
            STATE_A = new ConcreteStateA(this);
            STATE_B = new ConcreteStateB(this);
        }
    
        public void setCurrentSate(State currentSate) {
            this.currentSate = currentSate;
        }
    
        public void handle1(){
            this.currentSate.handle1();
        }
    
        public void handle2(){
            this.currentSate.handle2();
        }
    
    }
    public class Client {
    
        public static void main(String[] args) {
            //创建环境对象
            Context context = new Context();
            //初始化状态
            context.setCurrentSate(new ConcreteStateA(context));
            //执行动作
            context.handle1();
            context.handle2();
        }
    }
    

    巴士公交车的例子

      如果经常乘坐巴士或公交车的朋友可能比较熟悉,公交车有几个状态,开门、关门、行驶、停车,对应状态下的行为是有一些规则的,比如公交车在行驶过程中是不允许开门不能上人的,只有在停止状态下并且开门状态下才能上人,并且必须是关门状态下才能够启动开始行驶。
      下面的表格中,我列举了巴士的所有状态和行为:

    状态 开门 关门 启动 停止 上人 下人
    开门停止状态 N Y N N Y Y
    开门运行状态 N Y N Y N N
    关门停止状态 Y N Y N N N
    关门运行状态 N N N Y N N

      先来看一下,不用状态模式的情况下,也就是我们通常的做法,是如何写代码来处理这些情况的:

    //巴士类
    public class Bus {
    
        /**
         * 开车门
         */
        public void openDoor() {
    
        }
    
        /**
         * 关车门
         */
        public void closeDoor() {
    
        }
    
        /**
         * 巴士开始行驶
         */
        public void run() {
    
        }
    
        /**
         * 停止巴士
         */
        public void stop() {
    
        }
    
        /**
         * 乘客上车
         */
        public void pickUpPassenger() {
    
        }
    
        /**
         * 乘客下车
         */
        public void dropOffPassenger() {
    
        }
    }
    public class Client {
        static String state;
        public static void main(String[] args) {
            Bus bus = new Bus();
            if (state.equals("开门停止")) {
                bus.pickUpPassenger();
                bus.dropOffPassenger();
                bus.closeDoor();
            } else if (state.equals("开门运行")) {
                bus.closeDoor();
                bus.stop();
            } else if (state.equals("关门停止")) {
                bus.openDoor();
                bus.run();
            } else if (state.equals("关门运行")) {
                bus.stop();
            }
        }
    }

      没错,你可能看到了熟悉的代码:很多的if-else条件判断语句,不管这里的state变量是字符串还是整型的常量,相信你平时写代码时一定写过类似的代码,而且有的时候判断的情况非常之多,或者是你是用switch-case来处理,都是类似的情况。
      下面来看一下如何用状态模式来处理这些情况,我们前面讲状态模式是将动作行为委托到状态类,因此我们的思路就转变为首先去建立相关的状态类。

    实现代码:

    /**
     * 巴士抽象状态类
     */
    public abstract class BusState {
        /**持有Bus的引用*/
        protected Bus bus;
    
        public BusState(Bus bus) {
            this.bus = bus;
        }
    
        /**
         * 开车门
         */
        public abstract void openDoor();
    
        /**
         * 关车门
         */
        public abstract void closeDoor();
    
        /**
         * 巴士开始行驶
         */
        public abstract void run();
    
        /**
         * 停止巴士
         */
        public abstract void stop();
    
        /**
         * 乘客上车
         */
        public abstract void pickUpPassenger();
    
        /**
         * 乘客下车
         */
        public abstract void dropOffPassenger();
    }
    
    /**
     * 开门停止状态
     */
    public class OpenedStoppedState extends BusState {
    
        public OpenedStoppedState(Bus bus) {
            super(bus);
        }
    
        @Override
        public void openDoor() {
            //啥都不做,因为已经是开门状态下了不用再开门了
        }
    
        @Override
        public void closeDoor() {
            System.out.println("巴士关门了");
            //关门之后,巴士应该变成关门停止状态
            this.bus.setCurrentState(Bus.CLOSED_STOPPED_STATE);
        }
    
        @Override
        public void run() {
            throw new UnsupportedOperationException("开门停止状态下禁止行驶");
        }
    
        @Override
        public void stop() {
            //啥都不做,因为已经是停止状态下了不用再停止了
        }
    
        @Override
        public void pickUpPassenger() {
            System.out.println("乘客上车");
        }
    
        @Override
        public void dropOffPassenger() {
            System.out.println("乘客下车");
        }
    }
    
    /**
     * 开门运行状态
     */
    public class OpenedRunningState extends BusState {
    
        public OpenedRunningState(Bus bus) {
            super(bus);
        }
    
        @Override
        public void openDoor() {
            //do nothing 已经是开门状态了,实际上这也是一个非法行为你也可以抛出异常
        }
    
        @Override
        public void closeDoor() {
            System.out.println("巴士关门了");
            //关门后,巴士变成关门行驶状态
            this.bus.setCurrentState(Bus.CLOSED_RUNNING_STATE);
        }
    
        @Override
        public void run() {
            //do nothing 已经是运行状态了
        }
    
        @Override
        public void stop() {
            System.out.println("巴士停车了");
            //停车后,巴士变成开门停车状态
            this.bus.setCurrentState(Bus.OPENED_STOPPED_STATE);
        }
    
        @Override
        public void pickUpPassenger() {
            throw new UnsupportedOperationException("开门运行状态下禁止乘客上车");
        }
    
        @Override
        public void dropOffPassenger() {
            throw new UnsupportedOperationException("开门运行状态下禁止乘客下车");
        }
    }
    /**
     * 关门停止状态
     */
    public class ClosedStoppedState extends BusState {
    
        public ClosedStoppedState(Bus bus) {
            super(bus);
        }
    
        @Override
        public void openDoor() {
            System.out.println("巴士开门了");
            //开门后,巴士变成开门停止状态
            this.bus.setCurrentState(Bus.OPENED_STOPPED_STATE);
        }
    
        @Override
        public void closeDoor() {
            //do nothing 已经是关门状态了
        }
    
        @Override
        public void run() {
            System.out.println("巴士开始行驶");
            //行驶后,巴士变成关门运行状态
            this.bus.setCurrentState(Bus.CLOSED_RUNNING_STATE);
        }
    
        @Override
        public void stop() {
            //do nothing 已经是停止状态了
        }
    
        @Override
        public void pickUpPassenger() {
            throw new UnsupportedOperationException("关门停止状态禁止乘客上车");
        }
    
        @Override
        public void dropOffPassenger() {
            throw new UnsupportedOperationException("关门停止状态禁止乘客下车");
        }
    }
    /**
     * 关门运行状态
     */
    public class ClosedRunningState extends BusState {
    
        public ClosedRunningState(Bus bus) {
            super(bus);
        }
    
        @Override
        public void openDoor() {
            throw new UnsupportedOperationException("关门运行状态禁止开门");
        }
    
        @Override
        public void closeDoor() {
            //do nothing 已经是关门状态了
        }
    
        @Override
        public void run() {
            //do nothing 已经是运行状态了
        }
    
        @Override
        public void stop() {
            System.out.println("巴士停车了");
            //停车后,巴士变成关门停止状态
            this.bus.setCurrentState(Bus.CLOSED_STOPPED_STATE);
        }
    
        @Override
        public void pickUpPassenger() {
            throw new UnsupportedOperationException("关门运行状态禁止乘客上车");
        }
    
        @Override
        public void dropOffPassenger() {
            throw new UnsupportedOperationException("关门运行状态禁止乘客下车");
        }
    }
    public class Bus {
        /**分别代表四种状态*/
        public static BusState OPENED_STOPPED_STATE;
        public static BusState OPENED_RUNNING_STATE;
        public static BusState CLOSED_STOPPED_STATE;
        public static BusState CLOSED_RUNNING_STATE;
        /**当前状态*/
        private BusState mCurrentState;
    
        public Bus() {
            OPENED_STOPPED_STATE = new OpenedStoppedState(this);
            OPENED_RUNNING_STATE = new OpenedRunningState(this);
            CLOSED_STOPPED_STATE = new ClosedStoppedState(this);
            CLOSED_RUNNING_STATE = new ClosedRunningState(this);
        }
    
        /**
         * 设置当前的状态
         */
        public void setCurrentState(BusState state) {
            mCurrentState = state;
        }
    
        /**
         * 开车门
         */
        public void openDoor() {
            mCurrentState.openDoor();
        }
    
        /**
         * 关车门
         */
        public void closeDoor() {
            mCurrentState.closeDoor();
        }
    
        /**
         * 巴士开始行驶
         */
        public void run() {
            mCurrentState.run();
        }
    
        /**
         * 停止巴士
         */
        public void stop() {
            mCurrentState.stop();
        }
    
        /**
         * 乘客上车
         */
        public void pickUpPassenger() {
            mCurrentState.pickUpPassenger();
        }
    
        /**
         * 乘客下车
         */
        public void dropOffPassenger() {
            mCurrentState.dropOffPassenger();
        }
    }
    public class Client {
    
        public static void main(String[] args) {
            Bus bus = new Bus();
            //设置初始状态为关门运行状态
            BusState initState = new ClosedRunningState(bus);
            bus.setCurrentState(initState);
    
            //测试正常情况:停车->开门->下车->上车->关门->行驶
            bus.stop();
            bus.openDoor();
            bus.dropOffPassenger();
            bus.pickUpPassenger();
            bus.closeDoor();
            bus.run();
    
            //测试非正常情况1:关门行驶的时候去开门
            bus.setCurrentState(initState);
            bus.openDoor();
    
            //测试非正常情况2:门未关上就开始行驶
            bus.setCurrentState(new OpenedStoppedState(bus));
            bus.run();
        }
    }

    测试正常情况输出:
    这里写图片描述
    测试非正常情况1输出:
    这里写图片描述
    测试非正常情况2输出:
    这里写图片描述
      可以看到在状态模式实现的代码中,将以往的if-else条件判断转换为了四个相关的状态类来处理,客户端在使用的时候,无需关心当前是哪个状态,它只要执行具体的行为就可以,至于这些行为是否可以在当前状态下得到正确的响应完全由当前的状态类内部去处理。每一个状态类都拥有Context的所有的行为接口方法。在某一个状态类的内部实现中,我们看到,如果一个行为可以执行,那么就实现该行为的代码,如果一个行为在这个状态下是非法的或者禁止的,那么就抛出异常或者你什么也不做。

    理解状态和行为

      状态就是当前环境所处的情况或者是场景,在不同场景下当前环境对于不同行为要给出不同的响应,具体在代码中的体现可以理解为就是你的if-else判断。而行为就是你要执行的动作,你要做的事情,你要给出的响应。例如人冷了要加衣服,热了要脱衣服,冷热就是状态,而加衣脱衣就是行为。

      如图,状态模式下做的事情就是,由以往的Context上下文环境自己来挑选判断执行哪种行为,变成了由对应的状态类去挑选和执行哪种行为。状态类会对每一种行为都做出响应,这些响应可以是执行动作的响应,也可以是一种非法提醒的反馈响应,也可以什么都不做,这些要根据你的具体的业务来判断。对于环境来说,它的动作执行流程从表面上看是流畅的不被打断的(不被if-else的结构所破坏)。

    状态模式的优点

    • 结构清晰,避免了过多的 switch- case 或者 if- else 语句的使用,避免了程序的复杂性,提高系统的可维护性。
    • 封装性强,遵循设计原则,很好地体现了开闭原则和单一职责原则,每个状态都有一个子类负责,你要增加状态就要增加子类,你要修改状态,你只修改一个子类就可以了。另外也体现了迪米特法则,状态变换完全放到类的内部来实现,屏蔽了客户端调用的时候对状态处理的感知。

    状态模式的缺点
      缺点很明显,那就是子类会太多,因为每一个状态都对应一个子类,所以当你的状态非常多的时候就会发生类膨胀。

    状态模式和策略模式的区别

      状态模式和策略模式有着相同的类图, 但是它们的意图不同。策略模式更加侧重于行为或算法的替换,并且可以在运行时动态的任意替换,侧重点是使用不同算法族来解决问题。而状态模式更加侧重于状态的改变影响改变行为,而行为的执行结果又会导致状态发生变化,是一个状态和行为的变化过程。策略模式需要客户端必须完全知晓所有的策略方法,才能够知道究竟哪一个策略是当前需要的。而状态模式客户端在使用的时候,可以不必关心有哪些状态,他只需要去调用环境的行为就可以了,在环境的内部维护了这些状态。

    状态模式的使用场景

    • 行为随着状态的改变而改变的时候,这也是状态模式的根本出发点,例如权限设计,人员的状态不同即使执行相同的行为结果也会不同,在这种情况下需要考虑使用状态模式。
    • 条件、分支判断语句的替代者,在程序中大量使用 switch 语句或者if-else判断语句会导致程序结构不清晰,逻辑混乱,使用状态模式可以很好地避免这一问题。

      虽然状态模式可以很好的处理行为受状态约束的情况,但相应的对象的状态也会增加,所以在实际项目中使用的时候,要权衡利弊,考虑它对你的设计带来的后果影响是否可以接受。如果状态太多比如十几个或者几十个,还是建议不要使用了。


    参考:

    展开全文
  • 理解状态模式笔记

    千次阅读 2018-09-25 18:49:25
    23种设计模式中,并不都是晦涩难懂,有的简单,有的还需要理解,其中让我印象最深的是状态模式。当初理解这个模式还是废了一番周折,所以 这篇文章的目的还是梳理一下思路并记录一下,如果能帮到其他人就更好了。 让...
  • 状态模式简介及使用示例

    千次阅读 2019-06-04 17:29:48
    文章目录状态模式简介 状态模式简介
  • 设计模式之状态模式(State)

    千次阅读 2018-12-22 11:56:48
     什么是状态模式? 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理。最直接的解决方案是将这些所有可能发生的情况全都考虑到。然后使用if... ellse语句来做状态判断来进行不同情况的处理。但是.....
  • 状态模式总结-java版

    千次阅读 2019-02-01 09:54:50
    状态模式的简介 状态模式的抽象代码 状态模式的具体代码 状态模式的共享状态 状态模式的环境类改变状态 状态模式的优点 状态模式的缺点 状态模式的适用场景 状态模式的简介 状态模式用于解决系统中复杂对象...
  • 设计模式 ( 十七) 状态模式State(对象行为型)

    万次阅读 多人点赞 2012-05-21 14:42:22
    设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理。最直接的解决方案是将这些所有可能发生的情况全都考虑到。然后使用if... ellse语句...
  • 状态模式(十二)

    千次阅读 2019-06-12 23:13:05
    一个例子引出状态模式: 每天的不同时间工作会有不同的工作状态,我们用面向对象来实现一下: 工作类: public class Work { /** * 时间点 */ private int hour; /** * 工作是否完成 */ private boolean...
  • 状态模式(State)的定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类 ...
  • Java 设计模式——状态模式

    万次阅读 2019-11-07 12:21:38
    很多人在说状态模式的时候总拿策略模式来进行对比,可能他们的类图会有一点类似,可我却不认为他们有多么相像。你可以阅读《Java设计模式——策略模式》这篇博客,并与本文对比,以找到蛛丝马迹。 他们最根本的差异...
  • 但很多时候,简单粗暴的if else加标志位的方式并不能很地道地解决问题,这时,就可以运用到状态模式以及状态机来高效地完成任务。状态模式与状态机,因为他们关联紧密,常常放在一起讨论和运用。而本文将对他们在...
  • Java 有限状态机 (设计模式——状态模式) 编写代码的时候,有时会遇见较为复杂的swith...case...和if...else...语句。这一刻有时会想到状态机,用有限状态机替换swith...case...和if...else...可以: 降低程序的...
  • 【Java设计模式】状态模式

    千次阅读 2019-10-29 07:54:35
    文章目录概述适用场景优点缺点状态模式-相关设计模式演示 概述 ◆ 允许一个对象在其内部状态改变时,改变它的行为 ◆ 类型:行为型 适用场景 一个对象存在多个状态(不同状态下行为不同),且状态可相互转换 优点 ◆...
  • 设计模式——状态模式详解

    万次阅读 2017-07-05 11:52:21
    建议先看博文前半部分的理论介绍,再看后半部分的实例分析,最后再返回来复习一遍理论介绍,这时候你就会发现我在重点处标红的用心,对于帮助你理解设计模式有奇效哦~此篇总结整理设计模式中的状态模式。 1. 状态...
  • 设计模式入门———状态模式(State)

    千次阅读 2018-09-02 08:15:00
    本篇我将举两个例子来说明用不用状态模式对程序结构上的影响,以及状态模式所带来的好处 由于状态模式和策略模式类图基本一致,因此文末将做一些对比   情景引入  首先我们先看一个没加状态模式的简单例子,...
  • 《JAVA与模式》之状态模式

    千次阅读 2018-06-19 22:24:14
    在阎宏博士的《JAVA与模式》一书中开头是这样描述状态(State)模式的: 状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式。 状态模式允许一个对象在其内部状态改变的时候...
  • 状态模式(State Pattern)标签: 设计模式初涉描述性文字分离状态,选择实现定义当一个对象的内在状态发生改变时允许改变其行为,这个对象看起来像是改变了它的类三个角色 Context:上下文环境,定义客户感兴趣的接口...
  • Java状态模式(State)

    千次阅读 2019-04-17 00:18:17
      现实生活中我们经常会碰到状态改变的场景,面对不同的场景我们会做出不同的处理。比如: 电梯的运行 • 维修、正常、自动关门、自动开门、向上运行、向下运行...状态模式 使用场景   本案例我们通过宾馆入住的...
1 2 3 4 5 ... 20
收藏数 1,437,743
精华内容 575,097
关键字:

状态模式