写点什么

为了减少代码复杂度,我将 if-else 升级为面向状态编程

发布于: 刚刚

摘要:面向过程设计和面向对象设计的主要区别是:是否在业务逻辑层使用冗长的 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,不会复杂度超标。



点击关注,第一时间了解华为云新鲜技术~

发布于: 刚刚阅读数: 3
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
为了减少代码复杂度,我将if-else升级为面向状态编程