狀態模式主要解決的是當控制一個對象狀態轉換的條件表達式過於複雜時的狀況。把狀態的判斷邏輯轉移到表示不一樣狀態的一系列類當中,能夠把複雜的判斷邏輯簡化.java
一個複雜的業務中可能存在大量的 if else等邏輯條件判斷,對於後期維護來講是很是危險和複雜的。而狀態模式也是將與特定狀態相關的行爲局部化,而且將不一樣狀態的行爲分割開來.bash
能夠消除大量的條件分支語句,內部經過狀態轉移,來減小之間的相互依賴post
好比你在參與百度網盤開發,有如下常見場景:優化
會員等級 | 權限 |
---|---|
普通用戶 | 存儲照片、文件 |
會員 | 極速下載、5T空間... |
超級會員 | 小視頻自動備份、音視頻倍速播放... |
權限獲取類ui
package design.pattern;
import java.util.ArrayList;
public class UserRule {
/**
* 等級 1普通用戶 2會員 3超級會員
*/
private Integer level = 1;
/**
* 權限容器
*/
private ArrayList<String> ruleList = new ArrayList<String>() {
{
add("上傳文件");
add("下載文件");
}
};
public UserRule(Integer level) {
this.level = level;
}
/**
* 獲取權限列表
*
* @return
*/
public ArrayList<String> getRuleList() {
if (this.level == 2) { //會員
//todo 權限獲取
ruleList.add("極速下載");
ruleList.add("5T空間");
} else if (this.level == 3) { //超級會員
//todo 權限獲取
ruleList.add("光速下載");
ruleList.add("10T空間");
ruleList.add("小視頻自動備份");
ruleList.add("音視頻倍速播放");
}
return ruleList;
}
}
複製代碼
客戶端調用:this
Integer requestLevel = 3;
UserRule userRule = new UserRule(requestLevel);
ArrayList<String> ruleList = userRule.getRuleList();
//打印權限
System.out.println("會員等級" + requestLevel + "權限列表:");
for (Object object : ruleList) {
System.out.println(object);
}
複製代碼
output:spa
會員等級3權限列表:
上傳文件
下載文件
光速下載
10T空間
小視頻自動備份
音視頻倍速播放
複製代碼
彷佛看起來咱們的代碼足夠簡單,很好的知足了根據等級返回權限的需求code
咱們重點關注下獲取權限列表的根據不一樣的條件分支,處理不一樣的todo 的業務邏輯,若是咱們加入了更多的等級,更復雜的權限計算方式等等功能, 這個if else將會更加的龐大起來.cdn
剛剛說完可能龐大起來,產品過來又給我提v2.0的需求.視頻
咱們發現若是再加上返回下個版本的權限,真的是夠了,再過幾天不必定又出什麼需求,這個方法看起來都要崩潰了. 看來須要優化一下了。
首先咱們創建一個抽象類(核心做用方便子類約束和傳遞)
State.java
package design.pattern.Rules;
import design.pattern.UserRule;
import design.pattern.UserVo;
import java.util.ArrayList;
public abstract class State {
/**
* 用戶對象
*/
protected UserRule userRule;
/**
* 權限容器
*/
protected ArrayList<String> ruleList = new ArrayList<String>() {
{
add("上傳文件");
add("下載文件");
}
};
public State(UserRule userRule) {
this.userRule = userRule;
}
public abstract ArrayList<String> getRuleList(UserVo userVo);
}
複製代碼
第一步咱們須要簡單的參數對象(這裏用view object)
UserVo.java
package design.pattern;
public class UserVo {
private String name;
private Integer level;
public UserVo(String name, Integer level) {
this.name = name;
this.level = level;
}
public String getName() {
return name;
}
public Integer getLevel() {
return level;
}
}
複製代碼
繼承State.java狀態類,實現各自的會員返回類
package design.pattern.Rules;
import design.pattern.UserRule;
import design.pattern.UserVo;
import java.util.ArrayList;
/**
* 一類會員
*/
public class MemberOne extends State {
public MemberOne(UserRule userRule) {
super(userRule);
}
/**
* 獲取權限列表
*
* @return
*/
public ArrayList<String> getRuleList(UserVo userVo) {
//若是是一類會員(普通)
if (userVo.getLevel() == 1) {
return ruleList;
} else {
userRule.setState(new MemberTwo(userRule)); //設置下一級別類
return userRule.getRuleList(userVo); //獲取下一個級別的詳情
}
}
}
複製代碼
UserRule.java (橋樑類)
package design.pattern;
import design.pattern.Rules.MemberOne;
import design.pattern.Rules.State;
import java.util.ArrayList;
public class UserRule {
/**
* 具體權限對象
*/
private State currentRule;
public UserRule() {
currentRule = new MemberOne(this);
}
/**
* 設置權限對象
*
* @param state
*/
public void setState(State state) {
this.currentRule = state;
}
public ArrayList<String> getRuleList(UserVo userVo) {
return this.currentRule.getRuleList(userVo);
}
}
複製代碼
userRule類爲咱們優化前充滿了條件判斷的類,對他進行了解耦合.能夠理解爲對內調用類,對外暴露類的橋樑類
userVo對象是咱們的參數對象,這裏主要用於等級判斷. 若是不成立,則進行從新設置下一個處理規則類,並一樣調用規則列表方法。
剩下的兩個會員類
package design.pattern.Rules;
import design.pattern.UserRule;
import design.pattern.UserVo;
import java.util.ArrayList;
/**
* 三類會員
*/
public class MemberTwo extends State {
public MemberTwo(UserRule userRule) {
super(userRule);
}
/**
* 獲取權限列表
*
* @return
*/
public ArrayList<String> getRuleList(UserVo userVo) {
if (userVo.getLevel() == 2) {
ruleList.add("極速下載");
ruleList.add("5T空間");
return ruleList;
}else{
userRule.setState(new MemberThree(userRule));
return userRule.getRuleList(userVo);
}
}
}
複製代碼
package design.pattern.Rules;
import design.pattern.UserRule;
import design.pattern.UserVo;
import java.util.ArrayList;
/**
* 三類會員
*/
public class MemberThree extends State {
public MemberThree(UserRule userRule) {
super(userRule);
}
/**
* 獲取權限列表
*
* @return
*/
public ArrayList<String> getRuleList(UserVo userVo) {
//最高級
ruleList.add("光速下載");
ruleList.add("10T空間");
ruleList.add("小視頻自動備份");
ruleList.add("音視頻倍速播放");
return ruleList;
}
}
複製代碼
爲了參數方便傳遞管理,咱們單獨使用一個view object類.
UserVo.java
package design.pattern;
public class UserVo {
private String name;
private Integer level;
public UserVo(String name, Integer level) {
this.name = name;
this.level = level;
}
public String getName() {
return name;
}
public Integer getLevel() {
return level;
}
public void setName(String name) {
this.name = name;
}
public void setLevel(int level) {
this.level = level;
}
}
複製代碼
客戶端調用:
UserVo userVo = new UserVo("小紅", 1);
UserRule userRule = new UserRule();
ArrayList<String> ruleList = userRule.getRuleList(userVo);
//打印
System.out.println("用戶" + userVo.getName() + "當前權限以下:");
for (Object object : ruleList) {
System.out.println(object);
}
//他的下個權限能夠得到
userVo.setLevel(userVo.getLevel() + 1);
ruleList = userRule.getRuleList(userVo);
System.out.println("用戶" + userVo.getName() + "將要權限以下:");
for (Object object : ruleList) {
System.out.println(object);
}
複製代碼
output:
用戶小紅當前權限以下:
上傳文件
下載文件
用戶小紅將要權限以下:
上傳文件
下載文件
極速下載
5T空間
複製代碼
if (userVo.getLevel() == 1) {
return ruleList;
} else {
userRule.setState(new MemberTwo(userRule)); //設置下一級別類
return userRule.getRuleList(userVo); //獲取下一個級別的詳情
}
複製代碼
思考這段代碼存在的問題? 如何優化?
策略模式與狀態模式極其類似,可是兩者有其內在的差異
userRule.setState(new MemberTwo(userRule));),
複製代碼
對比策略模式: 策略模式詳解
更多精彩內容請關注熱情小宇公衆號(呆呆熊一點通)