一、什么是StateMode(狀態(tài)模式)
???狀態(tài)模式與上一篇寫(xiě)的《設(shè)計(jì)模式---Strategy模式》具體實(shí)現(xiàn)結(jié)構(gòu)有點(diǎn)相似豁生,兩者之間都是通過(guò)注入不同的子對(duì)象得到不同的操作行為耻瑟,但是兩者的實(shí)現(xiàn)目的完全不同蛉幸。例如革半,狀態(tài)模式的行為是平行,我們可以直接通過(guò)注入不同的狀態(tài)子類對(duì)象從而獲得不同狀態(tài)的操作舶斧,并且狀態(tài)是可以切換的欣鳖。而策略模式察皇,則是通過(guò)注入不同的操作對(duì)象從而獲得不同的操作行為茴厉,不同的注入方式直接,他們的行為是獨(dú)立的什荣。下面做一個(gè)區(qū)分:
(一)區(qū)別:
???狀態(tài)模式將各個(gè)狀態(tài)所對(duì)應(yīng)的操作分離開(kāi)來(lái)矾缓,即對(duì)于不同的狀態(tài),通過(guò)注入狀態(tài)稻爬,由不同的子類實(shí)現(xiàn)具體操作嗜闻,不同狀態(tài)的切換由子類實(shí)現(xiàn),當(dāng)發(fā)現(xiàn)傳入?yún)?shù)不是自己這個(gè)狀態(tài)所對(duì)應(yīng)的參數(shù)桅锄,則自己給Context類切換狀態(tài)琉雳;而策略模式是直接依賴注入到Context類的參數(shù)進(jìn)行選擇策略,不存在切換狀態(tài)的操作友瘤。
(二)聯(lián)系:
???狀態(tài)模式和策略模式都是為具有多種可能情形設(shè)計(jì)的模式翠肘,把不同的處理情形抽象為一個(gè)相同的接口,符合對(duì)擴(kuò)展開(kāi)放辫秧,對(duì)修改封閉的原則束倍。
總而言之!兩者就像孿生兄弟C讼贰P髅谩!
二柿究、該模式適應(yīng)范圍
(一)針對(duì)同一類型問(wèn)題有多種處理方式邮旷,具體行為也有差別的時(shí)候
(二)需要安全地封裝多種同一類型的操作時(shí)
(三)出現(xiàn)同一抽象類有多個(gè)子類,有需要通過(guò)if..else..或switch..case選擇具體子類時(shí)
三蝇摸、具體應(yīng)用
???筆者對(duì)于這個(gè)模式比較有感觸婶肩,這里先用電視機(jī)根據(jù)關(guān)機(jī)與開(kāi)機(jī)兩者不同狀態(tài),遙控器有不同操作行為作為案例分析探入。其次在通過(guò)我們實(shí)戰(zhàn)中狡孔,對(duì)于現(xiàn)在有一些APP應(yīng)用,不一定強(qiáng)制性要求登錄才可以進(jìn)行某些操作蜂嗽,因此則出現(xiàn)登錄與非登錄狀態(tài)的時(shí)候會(huì)出現(xiàn)不同的狀態(tài)苗膝,所以自然我們可以使用----狀態(tài)模式!V簿伞辱揭!
一离唐、電視機(jī)應(yīng)用---狀態(tài)模式
1.首先定義電視機(jī)操作接口
package cn.wsy.mymode.stateMode;
/**
* 電視機(jī)操作
* Created by wsy on 2016/2/23.
*/
public interface TvStateControl {
public void upVolume();
public void downVolume();
public void nextChannel();
public void beforeChannel();
}
2.不同狀態(tài)之間的電視機(jī)操作(開(kāi)機(jī)、關(guān)機(jī))
package cn.wsy.mymode.stateMode;
import android.util.Log;
/**
* Created by wsy on 2016/2/23.
*/
public class PowerOnState implements TvStateControl {
private final String TAG = "PowerOnState";
@Override
public void upVolume() {
Log.i(TAG,"音量提高中..,");
}
@Override
public void downVolume() {
Log.i(TAG,"音量降低中..,");
}
@Override
public void nextChannel() {
Log.i(TAG,"下一個(gè)頻道..,");
}
@Override
public void beforeChannel() {
Log.i(TAG,"上一個(gè)頻道..,");
}
}
package cn.wsy.mymode.stateMode;
import android.util.Log;
/**
* 關(guān)機(jī)的操作
* Created by wsy on 2016/2/23.
*/
public class PowerOffState implements TvStateControl{
private final String TAG = "PowerOffState";
@Override
public void upVolume() {
Log.i(TAG,"關(guān)機(jī)咯");
}
@Override
public void downVolume() {
Log.i(TAG,"關(guān)機(jī)咯");
}
@Override
public void nextChannel() {
Log.i(TAG,"關(guān)機(jī)咯");
}
@Override
public void beforeChannel() {
Log.i(TAG,"關(guān)機(jī)咯");
}
}
3.電視中遙控控制類
package cn.wsy.mymode.stateMode;
/**
* 電視機(jī)控制類
* Created by wsy on 2016/2/23.
*/
public class TvControl {
TvStateControl stateControl;
public TvControl(TvStateControl stateControl) {
this.stateControl = stateControl;
}
/**
* 這里作為切換狀態(tài)接口
* @param stateControl
*/
public void setStateControl(TvStateControl stateControl) {
this.stateControl = stateControl;
}
public void upVolume() {
stateControl.upVolume();
}
public void downVolume() {
stateControl.downVolume();
}
public void nextChannel() {
stateControl.nextChannel();
}
public void beforeChannel() {
stateControl.beforeChannel();
}
}
4.測(cè)試
???如果我們不采用模式設(shè)計(jì)程序问窃,一般我們?cè)O(shè)計(jì)思路會(huì)是if...else...硬編碼的判斷模式亥鬓,例如以下代碼:
public void traditionalTest(int tvState) {
//int tvState = 0;//0 開(kāi)機(jī) 1關(guān)機(jī)
//調(diào)聲音
upVolume(tvState);
//調(diào)頻道
nextChannel(tvState);
}
//傳統(tǒng)
public void upVolume(int state) {
if (state == 0) {
Log.i(TAG, "音量提高中..,");
}else{
Log.i(TAG, "關(guān)機(jī)啦..,");
}
}
public void downVolume(int state) {
if (state == 0) {
Log.i(TAG,"音量降低中..,");
}else{
Log.i(TAG, "關(guān)機(jī)啦..,");
}
}
public void nextChannel(int state) {
if (state == 0) {
Log.i(TAG,"下一個(gè)頻道..,");
}else{
Log.i(TAG, "關(guān)機(jī)啦..,");
}
}
public void beforeChannel(int state) {
if (state == 0) {
Log.i(TAG,"上一個(gè)頻道..,");
}else{
Log.i(TAG, "關(guān)機(jī)啦..,");
}
}
???這種方式,會(huì)增加更多if..else重復(fù)代碼域庇,可維護(hù)性也不高嵌戈,如果狀態(tài)增加,我們將要去每個(gè)涉及到狀態(tài)判斷的類文件去修改對(duì)應(yīng)邏輯听皿,這樣同樣違反了程序設(shè)計(jì)的封閉原則熟呛,不推薦!
???相反尉姨,利用狀態(tài)模式的實(shí)現(xiàn)代碼庵朝,如下:
public void modeTest() {
//注入狀態(tài)操作
TvControl tvControl = new TvControl(new PowerOnState());
//調(diào)聲音 開(kāi)機(jī)
tvControl.upVolume();
//關(guān)機(jī) 再操作
tvControl.setStateControl(new PowerOffState());
tvControl.nextChannel();
}
結(jié)果:
???相反,這種模式不用硬生生利用if..else..等判斷語(yǔ)句去處理又厉,再切換狀態(tài)的時(shí)候九府,我們只需要通過(guò)注入新的狀態(tài)子對(duì)象,即可以獲取不同的操作方式覆致!如果需求增加狀態(tài)屬性侄旬,我們也不需要直接去修改判斷語(yǔ)句,只需要重新增加狀態(tài)子對(duì)象篷朵,再次注入即可9磁!声旺!大大增加程序維護(hù)性笔链!
二、實(shí)戰(zhàn)應(yīng)用(登錄與非登錄行為)---狀態(tài)模式
???APP部分功能腮猖。這樣鉴扫,便會(huì)出現(xiàn)登錄與非登錄兩種狀態(tài)會(huì)出現(xiàn)不同的行為,因此這里便可以聯(lián)想到這篇博客學(xué)習(xí)的----狀態(tài)模式3喝薄F捍础!下面舉出簡(jiǎn)單例子(這里約定要登錄才能進(jìn)入個(gè)人中心姐赡、進(jìn)行評(píng)論莱预,進(jìn)行轉(zhuǎn)發(fā),否則會(huì)自動(dòng)進(jìn)入登錄界面项滑。)
1.涉及到登錄的所有行為 接口
package cn.wsy.mymode.stateMode.modeForLogin;
/**
* 涉及到登錄操作的行為動(dòng)作
* Created by wsy on 2016/2/23.
*/
public interface LoginState {
/**
* 進(jìn)入個(gè)人中心
*/
public void toPersonalCenter();
/**
* 進(jìn)行評(píng)論
*/
public void commenting();
/**
* 進(jìn)行轉(zhuǎn)發(fā)
*/
public void transpondMsg();
}
2.不同狀態(tài)的操作(登錄與非登錄)
package cn.wsy.mymode.stateMode.modeForLogin;
import android.util.Log;
/**
* 已經(jīng)登錄
* Created by wsy on 2016/2/23.
*/
public class LoginedState implements LoginState{
private final String TAG = "LoginedState";
@Override
public void toPersonalCenter() {
Log.i(TAG,"進(jìn)入個(gè)人中心界面");
}
@Override
public void commenting() {
Log.i(TAG,"進(jìn)行評(píng)論");
}
@Override
public void transpondMsg() {
Log.i(TAG,"進(jìn)行轉(zhuǎn)發(fā)");
}
}
package cn.wsy.mymode.stateMode.modeForLogin;
import android.util.Log;
/**
* 登出操作
* Created by wsy on 2016/2/23.
*/
public class LoginOutState implements LoginState{
private final String TAG = "LoginedState";
@Override
public void toPersonalCenter() {
Log.i(TAG,"進(jìn)入個(gè)人中心失敗依沮,進(jìn)入登錄界面");
}
@Override
public void commenting() {
Log.i(TAG,"進(jìn)行評(píng)論失敗,進(jìn)入登錄界面");
}
@Override
public void transpondMsg() {
Log.i(TAG,"進(jìn)行轉(zhuǎn)發(fā)失敗,進(jìn)入登錄界面");
3.登錄狀態(tài)行為操作靜態(tài)控制類
/**
* 登錄控制類
* Created by wsy on 2016/2/23.
*/
public class LoginControl {
LoginState loginedState;
public LoginControl(LoginState loginedState) {
this.loginedState = loginedState;
}
public void setLoginedState(LoginState loginedState) {
this.loginedState = loginedState;
}
public void toPersonalCenter() {
loginedState.toPersonalCenter();
}
public void commenting() {
loginedState.commenting();
}
public void transpondMsg() {
loginedState.transpondMsg();
}
}
4.測(cè)試結(jié)果
@Override
public void modeTest() {
LoginControl loginControl = new LoginControl(new LoginOutState());
//默認(rèn)沒(méi)有登錄
loginControl.toPersonalCenter();
//登錄后 再操作
loginControl.setLoginedState(new LoginedState());
loginControl.toPersonalCenter();
}
傻小孩b mark 共勉