狀態模式(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](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正在忙碌中······
~~~
- 前言
- 前言(目錄、源碼、資料)
- (一)簡單工廠模式(SimpleFatory)
- (二)工廠方法模式(FactoryMethod)
- (三)抽象工廠模式(AbstractFactory)
- (四)創建者模式(Builder)
- (五)原型模式(Prototype)
- (六)單例模式(Singleton)
- (七)外觀模式(Facade)
- (八)適配器模式(Adapter)
- (九)代理模式(Proxy)
- (十)裝飾模式(Decorator)
- (十一)橋模式(birdge)
- (十二)組合模式(Composite)
- (十三)享元模式(Flyweight)
- (十四)模板方法模式(Template)
- (十五)觀察者模式(Observer)
- (十六)狀態模式(State)