`
wsql
  • 浏览: 11755603 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

设计模式 (十六)状态模式(State)

 
阅读更多

状态模式(State)就是根据对象的状态不同,将有不同的行为。很简单的方法我们可以做N个

if(){
}
else if(){
}
...
...
else{
}
但是这样可想而知工作量会相当的大,这样就引入了状态模式,能实现和前面一样的功能,但是没有判断语句,而且如果添加了新的功能模块或者是流程,只要添加一个状态类就可以了。下面是简单的状态模式的原理图:


这里我用了一个QQ登录的状态来简单的模拟了一下状态模式,因为QQ从离线到登录到忙碌到离线就是一个很好的状态模式:

简单的画了一个原理图:

首先建立一个state接口,主要用于实现用,通过接口编程方便:

package com.designpattern.state;

public interface State {
	public void handle(QQ qq);
}

而后分别建立离线状态,Q我吧状态,忙碌状态,然后又回到离线,具体内容是一样的,就是一个状态里面的handle方法创建了下一个状态从而达到状态不断切换的功能:

package com.designpattern.state;

public class LeavingState implements State {

	@Override
	public void handle(QQ qq) {
		qq.setState(new LoginningState());
		System.out.println("QQ正在登陆在中······");
	}

}
package com.designpattern.state;

public class LoginningState implements State {

	@Override
	public void handle(QQ qq) {
		qq.setState(new ChattingState());
		System.out.println("QQ登陆成功,Q我吧······");
	}

}
package com.designpattern.state;

public class ChattingState implements State {

	@Override
	public void handle(QQ qq) {
		qq.setState(new BusyingState());
		System.out.println("QQ正在忙碌中······");
	}

}
package com.designpattern.state;

public class BusyingState implements State {

	@Override
	public void handle(QQ qq) {
		qq.setState(new LeavingState());
		System.out.println("QQ已经离线······");
	}

}
这样定义一个QQ类,主要是对QQ的各种状态的一个动态的变化,废话不多说,看代码就明了:

package com.designpattern.state;

public class QQ {

	private State state;

	public QQ() {
		state = new LeavingState();
	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		this.state = state;
	}

	public void handle() {
		state.handle(this);
	}
}
然后客户端调用输出:

package com.designpattern.state;

public class Client {
	public static void main(String[] args) {
		QQ qq = new QQ();
		qq.handle();
		qq.handle();
		qq.handle();
		qq.handle();
		qq.handle();
		qq.handle();
		qq.handle();
		qq.handle();
	}
}

QQ正在登陆在中······
QQ登陆成功,Q我吧······
QQ正在忙碌中······
QQ已经离线······
QQ正在登陆在中······
QQ登陆成功,Q我吧······
QQ正在忙碌中······
QQ已经离线······
这样就简单的模拟了QQ的一系列的状态;

状态模式使代码种复杂而庸长的逻辑判断语句问题得到了解决,而且具体状态角色将具体的状态和它对应的行为封装起来了,这使得增加一种新的状态变得十分简单。但是每一个状态对应一个具体的状态类,是结构分散,逻辑不是很清楚,阅读代码工作量会大一些。

看到这里我不禁思考了一个问题,既然用状态模式可以模拟QQ的一系列的状态,那么我的状态的改变也一样能通知好友,让好友时时的关注我的状态情况,这时我就想到了刚刚学到的Observer模式,就是一个观察啊,我就想了一下,把两个模式用到一起,把每一个状态的变化都通知自己所有的好友,不多说,马上做的Demo试试:

和上面一样首先建立了一个公用的接口State.java

接着模式QQ的四种状态,这里就粘贴了一个实例,不过都差不多:

package com.designpattern.state_observer;

public class ChattingState implements State {

	@Override
	public void handle(QQ qq) {
		qq.setState(new BusyingState());
		qq.setMessage("QQ正在忙碌中······");
	}

}
和上面不同的是堕落一个setMessage,这里是用来传递给QQ类,这样才能再次提醒观察的QQ好友,我的变化;

这里QQ类我定义成了一个抽象的类,不过大部分都封装好了,在让子类去继承的时候就继承一个handle方法就能实现操作,这样看起来比较简单:

package com.designpattern.state_observer;

import java.util.ArrayList;
import java.util.List;

public abstract class QQ {
	private List<Friends> friends = new ArrayList<Friends>();
	private String message;
	private String name = "halberd";
	private State state;

	public QQ() {
		this.state = new LeavingState();
	}

	public synchronized QQ addFriend(Friends friend) {
		friends.add(friend);
		return this;
	}

	public String getMessage() {
		return message;
	}

	public State getState() {
		return state;
	}

	public QQ handle() {
		this.state.handle(this);
		System.out.println(this.message);
		this.notifyFriends();
		return this;
	}

	public void notifyFriends() {
		for (int i = 0; i < friends.size(); i++) {
			Friends friend = (Friends) friends.get(i);
			friend.recevie(this.message, this.name);
		}
	}

	public synchronized QQ removeFriend(Friends friend) {
		friends.remove(friend);
		return this;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public void setState(State state) {
		this.state = state;
	}
}

其实很简单,就是把两个模式结合了一个,之后就是具体的实例对象:

package com.designpattern.state_observer;

public class MyQQ extends QQ {

	@Override
	public QQ handle() {
		return super.handle();
	}
	
}
我起名为MyQQ意为我的QQ,然后在用我的QQ好友实现Friends接口:

package com.designpattern.state_observer;

public interface Friends {
	public void recevie(String message,String name);
}
里面的两个参数一个是状态,一个是用户名(其实一个不写也行,我是想如果观察的不是我,就又可以复用了)

然后定义了两个朋友:

package com.designpattern.state_observer;

public class AndiMuise implements Friends {

	@Override
	public void recevie(String message, String name) {
		System.out.println("AndiMuise已经知道 " + name + " : " + message);

	}

}
客户端操作如下:

package com.designpattern.state_observer;

public class Client {
	public static void main(String[] args) {
		QQ qq = new MyQQ();
		qq.addFriend(new AndiMuise()).addFriend(new Steve());
		qq.handle().handle().handle();
	}
}

实例一个QQ对象,这里当然是我自己了,MyQQ这里如果是别人的直接再继承一下就行了,也不用修改代码,之后添加了两个QQ好友作为监听者,然后开始我一系列的状态的变化:

QQ正在登陆在中······
AndiMuise已经知道 halberd : QQ正在登陆在中······
Steve已经知道 halberd : QQ正在登陆在中······
QQ登陆成功,Q我吧······
AndiMuise已经知道 halberd : QQ登陆成功,Q我吧······
Steve已经知道 halberd : QQ登陆成功,Q我吧······
QQ正在忙碌中······
AndiMuise已经知道 halberd : QQ正在忙碌中······
Steve已经知道 halberd : QQ正在忙碌中······

这样就大功告成了,其实这样挺好的,慢慢学会把几个模式综合一下,因为重复的代码比较多,没有贴全,上传到了:

http://download.csdn.net/detail/wclxyn/4230476

初学笔记,还望批评指正

(后来改成了这个样子,就是能调用了setName方法,当然返回值是QQ,这样就省事了,关键是我比较懒)

package com.designpattern.state_observer;

public class Client {
	public static void main(String[] args) {
		QQ qq = new MyQQ();
		qq.setName("wclxyn").addFriend(new AndiMuise()).addFriend(new Steve())
				.handle().handle().handle();

		new MyQQ().setName("腾讯客服").addFriend(new AndiMuise()).addFriend(
				new Steve()).handle().handle().handle();
	}
}
QQ正在登陆在中······
AndiMuise已经知道 wclxyn : QQ正在登陆在中······
Steve已经知道 wclxyn : QQ正在登陆在中······
QQ登陆成功,Q我吧······
AndiMuise已经知道 wclxyn : QQ登陆成功,Q我吧······
Steve已经知道 wclxyn : QQ登陆成功,Q我吧······
QQ正在忙碌中······
AndiMuise已经知道 wclxyn : QQ正在忙碌中······
Steve已经知道 wclxyn : QQ正在忙碌中······
QQ正在登陆在中······
AndiMuise已经知道 腾讯客服 : QQ正在登陆在中······
Steve已经知道 腾讯客服 : QQ正在登陆在中······
QQ登陆成功,Q我吧······
AndiMuise已经知道 腾讯客服 : QQ登陆成功,Q我吧······
Steve已经知道 腾讯客服 : QQ登陆成功,Q我吧······
QQ正在忙碌中······
AndiMuise已经知道 腾讯客服 : QQ正在忙碌中······
Steve已经知道 腾讯客服 : QQ正在忙碌中······

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics