摘要:面向程序設計和面向物件設計的主要區別是:是否在業務邏輯層使用冗長的if else判斷,
本文分享自華為云社區《從面向if-else編程升級為面向狀態編程,減少代碼復雜度》,作者:breakDraw,
面向程序設計和面向物件設計的主要區別是:是否在業務邏輯層使用冗長的if else判斷,如果你還在大量使用if else,當然,界面表現層除外,即使你使用Java/C#這樣完全面向物件的語言,也只能說明你的思維停留在傳統的面向程序語言上,
需求
有一個非常經典的數字校驗場景, 需求如下:

復雜度高的硬寫代碼
這時候如果直接硬寫,大概率寫出容易復雜度巨高的代碼,還容易遺漏而出錯,
例子如下:
class Solution {
public boolean isNumber(String s) {
int sign = 1;
int pointSign = 1;
int eSign = 1;
int numSign = -1;
int i = 0;
int n = s.length();
while(i<n){
if(s.charAt(i)>='0'&&s.charAt(i)<='9'){
numSign = 1;
sign = -1;
}else if(s.charAt(i)=='+'||s.charAt(i)=='-'){
if(sign>0){
sign = -sign;
}else{
return false;
}
if(i>0&&s.charAt(i-1)=='.'){
return false;
}
}else if(s.charAt(i)=='.'){
//numSign = -1;
if(pointSign>0){
pointSign = -pointSign;
}else{
return false;
}
if(i>0&&(s.charAt(i-1)=='e'||s.charAt(i-1)=='E')){
return false;
}
}else if(s.charAt(i)=='e'||s.charAt(i)=='E'){
if(eSign<0||numSign<0){
return false;
}
eSign = -1;
sign = 1;
numSign = -1;
pointSign = -1;
}else{
return false;
}
i++;
}
return numSign>0;
}
}
這段代碼的復雜度為 21, 放在科目一考試直接不及格了,而且非常容易出錯,改著改著把自己改暈了,或者改漏了,

§ 狀態機優化
圖片參考自Leetcode官方題解,鏈接見:
https://leetcode-cn.com/problems/valid-number/solution/you-xiao-shu-zi-by-leetcode-solution-298l/

可以看到校驗的程序可以組成一個狀態, 當遇到特定字符時,進入特定的狀態去判斷,并且該狀態后面只能接入有限的狀態,因此我們可以定義N個狀態,每個狀態定義X個狀態變化條件和變化狀態,
在java中用多個map即可進行維護這種關系,
可以寫出如下的代碼, 雖然代碼量看起來更高了,但是可維護性和復雜度變強不少,
class Solution {
public enum CharType {
NUMBER,
OP,
POINT,
E;
public static CharType toCharType(Character c) {
if (Character.isDigit(c)) {
return NUMBER;
} else if (c == '+' || c == '-') {
return OP;
} else if (c == '.') {
return POINT;
} else if (c =='e' || c == 'E') {
return E;
} else {
return null;
}
}
}
public enum State {
INIT(false),
OP1(false),
// 在.前面的數字
BEFORE_POINT_NUMBER(true),
// 前面沒數字的點
NO_BEFORE_NUMBER_POINT(false),
// 前面有數字的點
BEFORE_NUMBER_POINT(true),
// 點后面的數字
AFTER_POINT_NUMBER(true),
// e/E
OPE(false),
// E后面的符號
OP2(false),
// e后面的數字
AFTER_E_NUMBER(true);
// 是否可在這個狀態結束
private boolean canEnd;
State(boolean canEnd) {
this.canEnd = canEnd;
}
public boolean isCanEnd() {
return canEnd;
}
}
public Map<State, Map<CharType, State>> transferMap = new HashMap<>() {{
Map<CharType, State> map = new HashMap<>() {{
put(CharType.OP, State.OP1);
put(CharType.NUMBER, State.BEFORE_POINT_NUMBER);
put(CharType.POINT, State.NO_BEFORE_NUMBER_POINT);
}};
put(State.INIT, map);
map = new HashMap<>() {{
put(CharType.POINT, State.NO_BEFORE_NUMBER_POINT);
put(CharType.NUMBER, State.BEFORE_POINT_NUMBER);
}};
put(State.OP1, map);
map = new HashMap<>() {{
put(CharType.POINT, State.BEFORE_NUMBER_POINT);
put(CharType.NUMBER, State.BEFORE_POINT_NUMBER);
put(CharType.E, State.OPE);
}};
put(State.BEFORE_POINT_NUMBER, map);
map = new HashMap<>() {{
put(CharType.NUMBER, State.AFTER_POINT_NUMBER);
}};
put(State.NO_BEFORE_NUMBER_POINT, map);
map = new HashMap<>() {{
put(CharType.NUMBER, State.AFTER_POINT_NUMBER);
put(CharType.E, State.OPE);
}};
put(State.BEFORE_NUMBER_POINT, map);
map = new HashMap<>() {{
put(CharType.E, State.OPE);
put(CharType.NUMBER, State.AFTER_POINT_NUMBER);
}};
put(State.AFTER_POINT_NUMBER, map);
map = new HashMap<>() {{
put(CharType.OP, State.OP2);
put(CharType.NUMBER, State.AFTER_E_NUMBER);
}};
put(State.OPE, map);
map = new HashMap<>() {{
put(CharType.NUMBER, State.AFTER_E_NUMBER);
}};
put(State.OP2, map);
map = new HashMap<>() {{
put(CharType.NUMBER, State.AFTER_E_NUMBER);
}};
put(State.AFTER_E_NUMBER, map);
}};
public boolean isNumber(String s) {
State state = State.INIT;
for (char c : s.toCharArray()) {
Map<CharType, State> transMap = transferMap.get(state);
CharType charType = CharType.toCharType(c);
if (charType == null) {
return false;
}
if (!transMap.containsKey(charType)) {
return false;
}
// 狀態變更
state = transMap.get(charType);
}
return state.canEnd;
}
}
可以看到復雜度也只有8,不會復雜度超標,

點擊關注,第一時間了解華為云新鮮技術~
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/307229.html
標籤:java
