V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
FrankFang128
V2EX  ›  程序员

把 throw error 当做 goto 使用是一个好的实践吗?

  •  
  •   FrankFang128 · 2018-05-09 00:57:55 +08:00 · 3036 次点击
    这是一个创建于 2389 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近我在做后台权限检验的时候有如下需求:

    1. 如果发现用户不满足条件 A,就返回响应 A',并停止后面的渲染
    2. 如果发现用户不满足条件 B,就返回响应 B',并停止后面的渲染
    3. 其他情况正常渲染资源详情

    由于要在很多接口里做类似的判断,所以我不太可能在每个接口里写 if...else。

    目前我的做法是在这些接口里调用一个 before_action (函数)

    如果 before_action 发现用户不满足条件,就抛出一个错误。

    然后在较高层面捕获这个错误,发送对应的响应 A' 或 B',同时由于 before_action 报错了,所以正常渲染逻辑就不会执行了。

    也就是说我在把 throw error 当做 goto 在使用:结束当前子程序,直接去执行另一段程序。

    大家平时也会这么写吗?

    14 条回复    2018-05-09 15:19:53 +08:00
    wellCh4n
        1
    wellCh4n  
       2018-05-09 01:08:44 +08:00
    摘自 阿里巴巴 Java 开发手册 第七章第四条
    ```
    [推荐] 表达异常的分支时,少用 if-else 方式,这种方式可以改写成:
    if (condition) { ...
    return obj; }
    // 接着写 else 的业务逻辑代码;
    说明:如果非得使用 if()...else if()...else...方式表达逻辑, [强制] 避免后续代码维
    护困难,请勿超过 3 层。
    ```
    此外,我司(技术栈 Java )在开发的时候校验参数条件经常使用 `断言`
    FrankFang128
        2
    FrankFang128  
    OP
       2018-05-09 01:16:24 +08:00
    这么多地方写一样的 if ... else 会很烦吧
    @wellCh4n 用断言然后不满足情况就报错么
    ss098
        3
    ss098  
       2018-05-09 01:32:39 +08:00 via Android
    可以考虑用 middle action 来解决?我一直是这样做权限检查的。
    FrankFang128
        4
    FrankFang128  
    OP
       2018-05-09 02:13:05 +08:00
    @ss098 middle action 阻止后面的渲染是怎么做的? 回调吗
    ss098
        5
    ss098  
       2018-05-09 03:48:24 +08:00 via Android
    @FrankFang128 https://laravel-china.org/docs/laravel/5.6/middleware

    Laravel 中间件的文档,可以看里面的例子理解下。

    就是如果判断不通过,就返回需要返回的内容。判断通过,就调用下一个函数,返回这个函数的值。
    dcoder
        6
    dcoder  
       2018-05-09 04:11:32 +08:00
    @FrankFang128
    我一直觉得 '异常' 基本就是个 goto 啊, 目的之一就是为了减少复杂的 if-else. 难道这个理解不对么?
    billlee
        7
    billlee  
       2018-05-09 07:51:03 +08:00
    这个就是异常的基本用法啊,在底层发现错误,高层统一处理
    zjsxwc
        8
    zjsxwc  
       2018-05-09 09:27:04 +08:00
    当然用抛异常了,更通用点,可以写一个正常无鉴权的类 CA 和一个专门鉴权的通用类 CB,CB 对象 IB1 持有这个无鉴权对象 IA1,IB1 就是对 IA1 的增强版了,然后注入替换 IA1 就行,以后有更多的类似 CA 这种类时都可以用一个 CB 对象注入替换,这样写的代码好处是完全没有副作用,**不需要更改原来任何的代码**
    wjpdev
        9
    wjpdev  
       2018-05-09 09:45:18 +08:00
    AOP
    puritania
        10
    puritania  
       2018-05-09 13:27:42 +08:00 via iPhone
    个人更喜欢抛异常一点,在最外层做好 catch 就好,无数的方法调用都可以抛出异常而不是各种 return 判断
    SakuraKuma
        11
    SakuraKuma  
       2018-05-09 13:43:44 +08:00
    个人也是抛异常,外面 catch 就好了。
    lihongjie0209
        12
    lihongjie0209  
       2018-05-09 13:43:50 +08:00
    可以使用 aop 在所有请求外面代理一下, 不满足权限的都不会进入业务代码.
    这里也不会涉及任何的异常, 只是把所有的 if 检查放到 aop 中而已
    xiaoshenke
        13
    xiaoshenke  
       2018-05-09 13:54:49 +08:00
    只有我一个人是在外面套一层 while(True),然后 break 么。。。
    scmod
        14
    scmod  
       2018-05-09 15:19:53 +08:00
    这种抛异常挺正常啊,如果这个异常只是为了当个 goto 一样的东西的话建议楼主自定义异常,重写 fillInStackTrace 返回 null 就行了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1273 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 23:34 · PVG 07:34 · LAX 15:34 · JFK 18:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.