if-else嵌套太深?教你一個新手都能掌握的設(shè)計模式搞定!
我也不用設(shè)計模式
很多人覺得自己寫的是業(yè)務(wù)代碼,按照邏輯寫下去,再把公用的方法抽出來復(fù)用就可以了,設(shè)計模式根本就沒必要用,更沒必要學(xué)。
一開始的時候,我也是這么想,直到我遇到。。。
舉個栗子
我們先看一個普通的下單攔截接口。
基本邏輯,參數(shù)安全攔截,次數(shù)攔截,規(guī)則攔截,都通過,返回允許下單,任意一個失敗,返回對應(yīng)的失敗原因。
多層嵌套if寫法
我們正常多層嵌套if的寫法
- /**
- * @author saier
- * @date 2020/3/31 18:03
- */
- public class Order {
- public Message interrupt1(){
- return null;
- }
- public Message interrupt2(){
- return null;
- }
- public Message interrupt3(){
- return null;
- }
- public Message interrupt4(){
- return null;
- }
- public Message interrupt5(){
- return null;
- }
- public static void main(String[] args) {
- Order order= new Order();
- if(order.interrupt1().getResult() == 1){
- if(order.interrupt2().getResult() == 1){
- if(order.interrupt3().getResult() == 1){
- if(order.interrupt4().getResult() == 1){
- if(order.interrupt5().getResult() == 1){
- System.out.println("success");
- }
- }
- }
- }
- }
- }
- }
- @Data
- class Message {
- private int result;
- private String msg;
- }
異常處理邏輯
或者有些利用異常做邏輯,代碼會簡單一點
- /**
- * @author saier
- * @date 2020/3/31 18:03
- */
- public class Order2 {
- public void interrupt1(){
- }
- public void interrupt2(){
- }
- public void interrupt3(){
- //失敗
- throw new RuntimeException();
- }
- public void interrupt4(){
- //失敗
- throw new RuntimeException();
- }
- public void interrupt5(){
- //失敗
- throw new RuntimeException();
- }
- public static void main(String[] args) {
- Order2 order2= new Order2();
- try{
- order2.interrupt1();
- order2.interrupt2();
- order2.interrupt3();
- order2.interrupt4();
- order2.interrupt5();
- System.out.println("success");
- }catch (RuntimeException e){
- System.out.println("fail");
- }
- }
- }
一開始,我就直接使用異常來做邏輯。但后續(xù)邏輯越來越復(fù)雜之后,也會出現(xiàn)一些問題。例如異常只能返回異常信息,不能返回更多的字段信息。
后面也留意到,異常做邏輯,在阿里規(guī)范是禁止的。
阿里代碼規(guī)范 :
【強制】異常不要用來做流程控制,條件控制。
說明:異常設(shè)計的初衷是解決程序運行中的各種意外情況,且異常的處理效率比條件判斷方式要低很多。
更重要的是,代碼可讀性太差了,隨時一個方法的異常拋出來,還要考慮代碼本身的異常。
沒更好的辦法,只能考慮設(shè)計模式了
怎么改,會使代碼的可讀性高,擴展性好?
在同事的提醒下,突然想起了設(shè)計模式!
我們希望達到的目的
- 代碼沒有這么多if else嵌套,可讀性高
- 如果新增新的攔截邏輯簡單方便,不影響原本的邏輯,擴展性好
- 可以很方便地調(diào)換攔截邏輯順序,低耦合
責(zé)任鏈模式
在這種場景下,非常適合責(zé)任鏈模式。(什么場景使用什么設(shè)計模式,這就需要平時有積累,知道各種設(shè)計模式的基本使用)
責(zé)任鏈,顧名思義,就是用來處理相關(guān)事務(wù)責(zé)任的一條執(zhí)行鏈,執(zhí)行鏈上有多個節(jié)點,每個節(jié)點都有機會(條件匹配)處理請求事務(wù),如果某個節(jié)點處理完了就可以根據(jù)實際業(yè)務(wù)需求傳遞給下一個節(jié)點繼續(xù)處理或者返回處理完畢。
首先,建立過濾器的抽象類
- public abstract class AbstractFilter {
- private AbstractFilter nextFilter;
- /**
- * 責(zé)任鏈的下一個元素
- */
- public void setNextFilter(AbstractFilter nextFilter){
- this.nextFilter = nextFilter;
- }
- public AbstractFilter getLastFilter(){
- if(this.nextFilter != null){
- return this.nextFilter.getLastFilter();
- }else{
- return this;
- }
- }
- public void filter(FilterRequest filterRequest, Response response){
- doFilter(filterRequest,response);
- if(response.isFilterNext() && nextFilter != null){
- nextFilter.filter(filterRequest,response);
- }
- }
- /**
- * 具體攔截邏輯
- */
- public abstract void doFilter(FilterRequest filterRequest, Response response);
- /**
- * 根據(jù)攔截結(jié)果做處理
- */
- public void exec(FilterRequest filterRequest, Response response){
- }
- }
過濾器的實現(xiàn)類
- @Component
- @Order(5)
- public class CheckParamFilter1 extends AbstractFilter {
- @Override
- public void doFilter(FilterRequest filterRequest, Response response) {
- }
- }
- @Component
- @Order(10)
- public class CheckParamFilter2 extends AbstractFilter {
- @Override
- public void doFilter(FilterRequest filterRequest, Response response) {
- }
- }
使用Order注解,確定過濾器的順序,后續(xù)在spring注入的時候,會有奇效
- //利用spring的自動注入機制
- @Autowired
- List<AbstractFilter> abstractFilterList;
- private AbstractFilter firstFilter;
- //spring注入后自動執(zhí)行
- @PostConstruct
- public void initializeChainFilter(){
- //把所有調(diào)用的邏輯注入到責(zé)任鏈,按照Order排序,越小優(yōu)先級越高
- for(int i = 0;i<abstractFilterList.size();i++){
- if(i == 0){
- firstFilter = abstractFilterList.get(i);
- }else{
- firstFilter.getLastFilter().setNextFilter(abstractFilterList.get(i));
- }
- }
- }
- //直接使用
- public Response exec(){
- firstFilter.filter(filterRequest, response);
- return response;
- }
使用設(shè)計模式的好處
看下使用責(zé)任鏈模式后,有什么好處!
- 新增攔截邏輯,只需要再實現(xiàn)一個AbstractFilter類即可
- 修改攔截順序,只需要修改Order注解的大小,越小,優(yōu)先級越高
- 代碼清晰,所有處理邏輯下沉到實現(xiàn)類中
使用設(shè)計模式的缺點
做到了低耦合,高擴展。但也帶來了一些不好的地方
- 邏輯更復(fù)雜,用了鏈?zhǔn)降葦?shù)據(jù)結(jié)構(gòu),要注意單例的問題,不能重復(fù)使用
- 類數(shù)量激增,一個攔截器就一個類
最后小結(jié)一下
不是什么地方都適合使用設(shè)計模式,如果邏輯簡單,你硬要使用設(shè)計模式,只會帶來結(jié)構(gòu)上的復(fù)雜,大家可以按照大家的業(yè)務(wù)場景來使用。
關(guān)于作者:南山獅:理工男,7年互聯(lián)網(wǎng)電商系統(tǒng)開發(fā)經(jīng)驗,知識分享領(lǐng)域探索小白。