在推进项目开发工作的时候, 大家经常会碰见这么一种情况, 就是之前已经把某个功能函数给写好了, 但是又想让它多出一些别的本事来, 不过心里又盘算着, 绝对不想去动这个老函数里面的那一堆代码。比方说, 要算一下跑这个函数花了多少时间, 或者是想要多记几笔日志, 还得搞个权限查查、异常抓抓什么的。
那装饰器, 它就是专管这种事儿的厉害工具。它能够在完全不碰原有函数源码的那条底线的前提下, 顺手就给函数加上各种新花样, 同时, 这也是在企业里进行开发时, 使用频率超级高的一项高级语法技巧。
可以把装饰器这种技术的本质理解成是对函数进行的一种包装处理, 因为在这个场景里, 函数属于一等对象, 这一类对象是可以被当作参数来传递使用的, 同时也是可以被当作返回结果给返回出去的, 装饰器就是因为看中了这个特性才会去接收那个旧的函数作为入参, 然后它会在该旧函数的内部去增加一些前置或者后置的附加逻辑, 最后再把经过了包装之后的新函数再返回回去, 这样一来, 原来那些业务代码就被完全保留下来了, 新增的那些逻辑就全部统一地放到了装饰器的内部里面去了, 从而就这样实现了业务逻辑和处理这些附加功能之间的解耦状况。
它的核心优势, 实际上是代码复用这件事情, 多个函数都需要同样的附加逻辑的话呢, 是不需要每个函数内部重复编写一遍的, 只需要写好一份装饰器, 给目标函数直接挂载即可, 后期修改附加逻辑的话, 只改动装饰器一处就可以了, 所有使用它的函数全部同步生效, 维护是十分方便的。
装饰器可以实现很多实用能力。统计函数执行时间,用来分析代码性能;接口调用前做权限校验;函数执行自动打印运行日志;统一捕获函数内部异常;做缓存处理,重复调用直接返回缓存结果,减少重复运算。
对于新手朋友来说, 在学习使用装饰器这一过程当中, 是非常容易碰到若干个难以攻克的难点的。比方说, 当一个函数被装饰器进行处理并且完成包装之后, 该原函数的某些具体属性就会出现变化的情况, 那么当开发人员在调试代码并且需要查看函数相关信息的时候就容易产生一种混淆不清的状态。
此外, 如果这个装饰器是需要带有参数的, 那么这种带参数的装饰器的写法就会变得更加复杂一些, 这便要求我们自己去分清其中存在有多层嵌套的逻辑关系, 千万不要因为看到了这层层嵌套的结构就被吓住了, 要保持一个冷静的心态去处理这种情况。
装饰器这个东西啊, 不是哪儿都必须要用的。要是写那种特别简单、篇幅也短小的脚本, 功能还比较单一的话, 非要硬着头皮去写装饰器, 那就会把理解的成本给搞高起来的。
它比较适合用在几个特定的场合, 第一个是多个函数都需要用到同一套额外的逻辑;第二个是一些原来的业务代码, 因为各种各样的原因不允许随便改动, 但是又需要增加一些横向拓展的能力的时候用得上;还有一个地方就是框架的最底层, 你看现在很多第三方的库, 他们都大量地在使用装饰器来对功能进行拓展的。
能够看懂并且能够使用装饰器, 这就代表了对函数的理解提升到了一个全新的层次。其实不需要去深挖那些复杂且底层的实现原理, 只需要先搞懂“包装、增强功能、不去改动原有代码”这个核心思想就可以了。
只要能够在别人的项目里看明白他们是怎么用装饰器的, 然后逐步地去尝试在一些简单的场景里使用它, 就肯定能够体会到装饰器所带来的方便之处。