`
BestUpon
  • 浏览: 290082 次
  • 性别: Icon_minigender_1
  • 来自: 兰州
社区版块
存档分类
最新评论

状态模式(State)

阅读更多

请参看:状态模式续.

http://bestupon.iteye.com/blog/693520

 

一、引言

 

如果你现在在设计一个交通控制程序,目前可能只有三种颜色,有可能你会将其写成如下的代码形式。

TrafficLight 代码:

 

package org.bestupon.dp.state;

public class TrafficLight {
	private static enum State {
		RED, GREEN, YELLOW
	}

	private static State state = State.RED;

	public static void change() {
		switch (state) {
		case RED:
			System.out.println("红灯");
			sleep(5000);
			state = State.GREEN;
			break;
		case GREEN:
			System.out.println("绿灯");
			sleep(5000);
			state = State.YELLOW;
			break;
		case YELLOW:
			System.out.println("黄灯");
			sleep(1000);
			state = State.RED;
		}
	}

	private static void sleep(int second) {
		try {
			Thread.sleep(second);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

 

 Client代码:

 

package org.bestupon.dp.state;

public class Client {

	public static void main(String[] args) {
		while (true) {
			TrafficLight.change();
		}
	}

}
 

 

 

在以上的模式的设计基础上完成了功能,但是如果状态(红绿灯颜色)增多了呢?是不是还要修改源码呢?是不是还要修改switch语句呢?这样是不是整个流程会变得冗长呢?或者是状态是不间断的平凡的变换的呢?也就是说在{红、黄、绿}->{红、黄、绿、蓝}->{红、黄、绿、黑}->{红、黄、绿、其他}->{其他}这样不定的变换,是不是代码要平凡的修改呢?

我们终于看见了自己写的代码还是不够的灵活,那怎么才能让其变的灵活、适应各种情况呢?我们就从重构出发看看怎么解决我们的问题。

那么什么是重构呢?又如何样重构呢?

二、重构

 

重构:

 

1.       对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。

2.       使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。

3.       通俗的说法:重构是一种高效且受控的代码整理技术。

 

实现红绿灯之间状态的变化主要是依靠switch语句来改变状态的,在重构方法上有这么一条Replace Type Code with State/Strategy 这么一种手段。那么究竟是选择State模式还是Stratey模式呢?分析我们的问题主要是解决状态变化多端,而State就是(变化多端),Stratey(明修栈道、暗渡乘沧)。那么什么是状态模式呢?

 

三、状态模式

 

定义: 根据对象的状态不同,将具有不同的行为。

UML图:

 

使用时机:

         当一个对象的行为取决于他的状态,并且它必须在运行时刻根据状态改变他的行为,或者一个操作中还有庞大的多分支的条件语句,并且这些分支依赖于该对象的状态时,就需要适应状态模式。

四、分析

 

回忆上面的代码,其有很多的分支(switch语句),伴随着状态的增加,条件分支将越来越复杂,并且所依赖每一种状态都有不同的行为(每个case都有不同的动作),所以我们可以依据状态模式重构他。

下面看看,我们如何使用状态模式(State)来重构它。

五、办法

 

1.       TrafficLight 瘦身:

每一中状态抽象到一个类中去(LightState),为了每次都能很清楚的知道下一个状态是什么状态,我们设计change()中增加一个下次状态的LightState参数。

TrafficLight代码如下:

 

package org.bestupon.dp.state.refactor;
/**
 * 
 * @author BestUpon
 * @email bestupon@foxmail.com
 * @date 2010-6-15下午05:21:47
 * @ask
 * @answer
 */
public class TrafficLight {

	private LightState current = null;

	public void set(LightState state) {
		this.current = state;
	}

	public void change(TrafficLight light,LightState firstState,LightState nextState) {
		current = firstState;
		current.change(this,current);
	}
} 

 

LightState 代码如下:

package org.bestupon.dp.state.refactor;
/**
 * 
 * @author BestUpon
 * @email bestupon@foxmail.com
 * @date 2010-6-15下午05:21:00
 * @ask
 * @answer
 */
public interface LightState {
	public void change(TrafficLight light,LightState nextState);
} 

2. 增加一层对个状态的控制层, abstract Light 类:让Light 去实现LightState接口。确保状态和操作绑定在一起。

Light 代码如下:

 

package org.bestupon.dp.state.refactor;

/**
 * 
 * @author BestUpon
 * @email bestupon@foxmail.com
 * @date 2010-6-15下午05:21:15
 * @ask
 * @answer
 */
public abstract class Light implements LightState {

	@Override
public abstract void change(TrafficLight light, LightState nextState);
	protected void sleep(int second) {
		try {
			Thread.sleep(second);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

 

 

3. 让没一个真正的状态去实现Light这个抽象类.

//红:
package org.bestupon.dp.state.refactor;
public class RedLight extends Light {
	@Override
	public void change(TrafficLight light, LightState nextState) {
		System.out.println("红灯");
		sleep(5000);
		light.set(nextState); //考虑弹性调整状态,可以不用写死状态对象设定

}
}
//黄:
package org.bestupon.dp.state.refactor;
public class YellowLight extends Light {

	@Override
	public void change(TrafficLight light,LightState nextState) {
		System.out.println("黄灯");
		sleep(1000);
		light.set(nextState);
	}
}
//绿:
package org.bestupon.dp.state.refactor;
public class GreenLight extends Light {

	public void change(TrafficLight light, LightState nextState) {
		System.out.println("绿灯");
		sleep(5000);
		light.set(nextState);

	}
}

 

 

 4.客户端

 

 

package org.bestupon.dp.state.refactor;
/**
 * 
 * @author BestUpon
 * @email bestupon@foxmail.com
 * @date 2010-6-15下午05:23:47
 * @ask 
 * @answer
 */
class Client {
	public static void main(String[] args) {

		TrafficLight trafficLight = new TrafficLight();

		// LightState states [] = {new RedLight(), new YellowLight(), new GreenLight(),new YellowLight() };
		LightState states[] = StateHolder.getStates();

		int index = 0;
		while (index != states.length) {
			trafficLight.change(trafficLight, states[index], index == states.length - 1 ? states[index] : states[index + 1]);
			index++;
			if (index == states.length)
				index = 0;
		}
	}
}
 

 

5.为了在下次修改状态和状态次序的时候不修改客户端,将其封装在了一个工具类中StateHolder中。

 

package org.bestupon.dp.state.refactor;
/**
 * 
 * @author BestUpon
 * @email bestupon@foxmail.com
 * @date 2010-6-15下午08:11:33
 * @ask
 * @answer
 */
public class StateHolder {
	private static LightState[] states = null;
	public static LightState[] getStates(){
		if(null == states) {
			LightState[]statestemp= {new RedLight(), new YellowLight(), new GreenLight(),new YellowLight() };
			states = statestemp;
		}
		return states;
	}
}

 优点

         状态模式使用代码中复杂而庸长的逻辑判断语句问题得到了解决,而且状态角色将具体的状态和他对应的行为封装了起来,这使得增加一种新的状态显得十分简单。

      缺点:

         使用状态模式时,每个状态对应一个具体的状态类,使结构分散,逻辑不太清楚,阅读代码时比较困难。

         评论:

现在线程是休眠时间直接写在了类中,本程序依然还有重构的价值!

 

附件:源程序doc文档

 

 

 

 

 

 

 

  • 大小: 21.5 KB
分享到:
评论
6 楼 cloud21 2010-06-17  
很不错,学习过。
5 楼 抛出异常的爱 2010-06-17  
BestUpon 写道
iaimstar 写道
枚举各种万能
既然你用了枚举,为啥不用枚举来写状态模式


枚举虽然遍历的时候也是以自然顺序的,但是直观上数组的顺序性比较直观!也容易理解上一个状态和下一个状态的关系!



enum Light{
    红灯(1000),黄灯(5000),绿灯(5000);    //顺序调整.
    int sleepping;
    private Light(int x) {
        this.sleepping = x ;        
    } 
    public Light change(){
        System.out.println(name());
        sleep();
        return next();
    }
	
    public Light next(){
        return values()[((ordinal()+1)%(values().length))];
    }
    public static void main(String[] args) {
		Light light = Light.红灯;
    	while(true){
			light = light.change();
		}
	}
    private void sleep() {
		try {
			Thread.sleep(this.sleepping);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
4 楼 lj9799616 2010-06-17  
在你的Client里面
trafficLight.change(trafficLight, states[index], index == states.length - 1 ? states[index] : states[index + 1]);

这句当index==3时所指的nextState是不是不对啊  指向了currentState


package org.bestupon.dp.state.refactor;
/**
*
* @author BestUpon
* @email bestupon@foxmail.com
* @date 2010-6-15下午05:23:47
* @ask 状态模式客户端
* @answer
*/
class Client {
public static void main(String[] args) {

TrafficLight trafficLight = new TrafficLight();
LightState states[] = StateHolder.getStates();
int index = 0;
while (true) {
if(index != states.length)
{
trafficLight.change(trafficLight, states[index], index == states.length - 1 ? states[0] : states[index+1]);
index++;
}else
{
index=0;
}


}
}
}
3 楼 iaimstar 2010-06-17  
说实话真没看出啥可读性来
            trafficLight.change(trafficLight, states[index], index == states.length - 1 ? states[index] : states[index + 1]);  

着看着多蛋疼啊
2 楼 BestUpon 2010-06-17  
iaimstar 写道
枚举各种万能
既然你用了枚举,为啥不用枚举来写状态模式


枚举虽然遍历的时候也是以自然顺序的,但是直观上数组的顺序性比较直观!也容易理解上一个状态和下一个状态的关系!
1 楼 iaimstar 2010-06-17  
枚举各种万能
既然你用了枚举,为啥不用枚举来写状态模式

相关推荐

    状态模式 State Pattern

    ### 状态模式(State Pattern) #### 概念与定义 状态模式是一种行为设计模式,它允许对象在其内部状态改变时改变其行为,使对象看起来像是修改了它的类。该模式通过引入一个代表各种状态的类以及一个行为随着这些...

    设计模式之状态模式State

    状态模式通常包含三个主要角色:Context(上下文)、State(抽象状态)和ConcreteState(具体状态)。 上下文是拥有状态的对象,它定义了与该状态相关的接口,并负责在适当的时候将请求委托给相应的状态对象处理。...

    每天感悟总结-状态模式State

    2009-03-10模式State:一个事件(消息)引起环境或数据的变化,可能导致状态变化,于是处理流程改变,这里的状态是把处理流程分成了很多阶段,通过状态机来根据传来的事件(消息)引发状态转换,管理状态属性和状态行为,...

    设计模式C++学习之状态模式(State)

    状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了它的类。这种模式常用于处理对象的状态变化,并且使代码结构清晰,易于维护。 在C++中,状态模式通常包含以下几个关键...

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

    状态模式是一种行为设计模式,它使对象能够在内部状态改变时改变其行为,看起来好像改变了它的类。这种模式常用于处理对象在不同状态下表现各异的情况,避免了复杂的条件语句,提高了代码的可读性和可维护性。 在...

    Android的状态机模式StateMachine与State

    在博文《Android的状态机模式StateMachine与State》中,作者可能会详细介绍如何创建和使用这两种组件。通常,状态机的实现会涉及到以下步骤: 1. **定义状态接口或抽象类**:创建一个State接口或抽象类,其中包含...

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

    状态模式是一种行为设计模式,它使你能在运行时改变对象的行为。在状态模式中,一个对象的状态变化会导致其行为的变化,这种变化不是通过改变对象的类来实现的,而是通过改变对象的状态。这个模式的核心是封装可能...

    Head First 设计模式 (十) 状态模式(State pattern) C++实现

    状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了它的类。这种模式常用于处理对象的状态变化,并且根据不同的状态,对象的行为也相应地变化。在C++中实现状态模式,我们...

    JackChan1999#Java-Degisn-Patterns#状态模式-State Pattern1

    状态模式-State Pattern状态模式-State Pattern【学习难度:,使用频率:】状态模式-State Pattern处理对象的多种状态及其相互

    《设计模式》实战---状态模式(State Pattern)

    在《设计模式》实战---状态模式(State Pattern)这篇文章中,作者可能详细探讨了以下关键点: 1. **模式定义**:状态模式允许对象在内部状态改变时改变其行为,对象看起来好像修改了它的类。这通过将每个状态封装...

    设计模式 - 状态模式(C++实例)

    在C++中实现状态模式,我们通常会定义一个抽象状态类(State),它声明了所有可能的状态行为。然后,创建一系列具体状态类(ConcreteState)来实现这些行为。每个具体状态类代表一种特定的状态,并且在内部维护当前...

    状态模式(State Pattern)是一种行为设计模式

    状态模式(State Pattern)是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了它的类。这种模式将一个对象的行为分解为各个独立的状态,并且每个状态都封装在自己的类中,使得对象在...

    设计模式State模式源码

    State模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If elseif else 进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了. 不只是根据状态,也有根据属性.如果...

    状态模式代码示例

    在提供的压缩包`state.zip`中,很可能包含一个简单的状态模式实现,可能包括`Context`、`AbstractState`和几个`ConcreteState`类。这些类的结构可能是这样的: ```java // Context public class Context { ...

    C#面向对象设计模式纵横谈(22):(行为型模式) State 状态模式

    标题和描述均提到了"C#面向对象设计模式"中的State状态模式,这表明文章的核心内容是围绕State模式在C#编程语言中的应用展开。State模式是一种行为设计模式,旨在允许对象在其内部状态改变时,其行为也能相应地改变...

    c++状态模式

    状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,对象看起来似乎修改了它的类。在C++中,状态模式通常通过定义一系列的类来表示各种状态,并用一个上下文类来管理这些状态的切换。下面将详细...

    管理订单状态,该上状态机吗?轻量级状态机COLA StateMachine保姆级入门教程.doc

    在订单状态管理中,状态机模式是一种常用的解决方案,但是在实际项目中,状态机的使用率并没有想象中那么高。笔者在电商领域进行后端开发时,发现了状态机的重要性,但是在使用 Spring StateMachine 时,发现了它的...

    java 设计模式之状态模式

    状态模式是一种行为设计模式,它允许对象在内部状态改变时改变其行为,看起来好像对象改变了它的类。在Java中,状态模式通常通过定义不同的状态类和一个上下文类来实现,其中上下文类持有状态对象并调用其方法来响应...

    设计模式:状态模式TCPConnection案例

    状态模式是一种行为设计模式,它使你能在运行时改变对象的行为。在TCP连接中,状态模式的应用尤为常见,因为TCP连接在不同的阶段会有不同的行为,比如建立连接、数据传输、断开连接等。下面我们将详细探讨这个模式...

Global site tag (gtag.js) - Google Analytics