-->

左耳听风_035_34_编程范式游记5-_修饰器模式

你好,我是陈浩网密鹰,左耳朵house.在上一讲中呢,我们领略了函数式编程的趣味和魅力。

主要呢讲了一些函数式编程的主要技术,你还记得有哪些吗?有递归map reduce,还有filter等等。

我们还利用了python decorator和generator功能,将多个函数啊组合成了管道。

你心中呢可能会有一个疑问,那这个decorator又是怎么工作的呢?那这个呢就是这一讲要讲述的内容,decorate模式啊又叫做修饰器模式啊或者装饰器模式。

我们首先来谈一谈python的decorator.那python的decorator呢在使用上和java的annotation以及c sharp的attribute很相似,就是在方法名前面啊加一个艾特叉叉叉的注解来给这个方法装饰一些东西。

但是呢java和c sharp annotation太过于复复杂了。

你要玩它呢,需要先了解一堆的的内库文档,那感觉呢几乎就是在学另外一门语言。

而python呢使用了一种相对于decorator pattern和annotation来说非常优雅的方法。

那这种方法呢不需要你去掌握什么复杂的OO模型啊,或者是annotation的各种类库规定。

完全呢就是语言层面的玩法,是一种函数式编程的技巧。

那这个呢是我最喜欢的一个模式了啊,也是一个挺好玩的东西。

那这个模式呢动用了函数式编程的一个技术啊,就是用一个函数来构造另一个函数。

好了,我们先来点感性认识,我们来看一下文中的这段python修饰器的hello word代码,还有它的执行结果。

那从中呢你可以看到这么几点东西。

那第一呢函数号前面有一个叫做at hello的注解。

那这个hello呢就是我们前面定义的函数。

Hello.那第二呢在hello函数中啊,它需要一个叫做FN的参数,那这个呢就是用来做回调的函数。

那第三呢这个hello函数啊返回了一个inner函数rarapper.而这个rapper呢回调了传进来的FN,并且呢在回调前后加了两条语句。

那对于python的这个注解,语法堂来说呢,当你在用一个叫decorator的注解来修饰一个叫funk的函数的时候呢,它的解释器啊就会把它解释成funk,等于decorator funk.你看这不就是把一个函数当做参数传到另一个函数中,然后再回调吗?是的,但是呢我们需要注意,这里呢还有一个赋值语句啊,把decorator这个函数的返回值啊赋制回了原来的funk.我们再来看一个带参数的玩法。

在文中的这个例子里呢,我们可以看到make HTML tag有两个参数。

所以呢为了让hello被make TML tag修饰成功,make HTML tag必须返回一个decorator.那这样一来呢,我们就可以进入到decorator的逻辑中了。

那decorator呢得返回一个rapper, rapper里呢回调。

Hello,看似那个max TML tag写的层层叠叠,但是呢已经了解了本质的,我们啊会觉得写的很自然。

我们再回到文中啊,看一个给其他函数加缓存的示例。

那这个例子呢是一个斐波纳契数列的递归算法,我们知道这个递归啊是相当没有效率的,因为会重复调用。

比如呢我们要计算部五,那需要把它分解成废部。

四加上肺部三,而肺部四呢会分解成肺部,三加肺部二,而肺部三呢又分解成肺部。

二加上肺部一,所以你可以看到,基本上来说呢废物三fab二、废物一在整个递归过程中啊被调用了至少两次。

而我们用decorator呢,在调用函数之前啊查询一下缓存啊,如果没有才调用,有的呢就从缓存中返回值。

那这个递归啊一下子就从二叉树式的递归啊变成了线性的递归。

那代码中raps注解的作用呢是保证废物的函数名,不被recorer所取代。

呃,除此之外呢,python啊还支持类方式的decorator.那文中的这个事例呢,用类的方式啊来声明了一个decorator.我们可以看到这个类中呢有两个成员,那一个呢是下划线unit.那这个方法呢是在我们给某个函数啊做decorate的时候啊被调用。

所以呢就需要有一个FN的参数啊,也就是被decorate的函数。

那还有一个呢是下划线扣,那这个方法呢是在我们调用被代号reader的函数时啊被调用的那从这段代码的输出中呢,可以看到整个程序的执行顺序。

那这个看上去啊要比函数式的方式更易读一些。

我们再来看一个实际讲的例子。

那接下来呢,文中这个事例展示了通过UL的路由来调用相关注册的函数。

那这里我们要注意这个世列中的decorator类啊,不是真正的decorator,那其中呢也没有下划线靠,而且呢wrapper返回了原函数,所以呢原函数啊没有发生任何变化。

那以上呢就是python的decorator.那接下来呢我们来讲一下构元的decorator, python呢有语法堂啊,所以写出来的代码比较酷。

但是对于没有修饰区语法堂这类语言写出来的代码会是什么样的呢?我们来看一下构元的代码是怎么写的,还是从一个hello world开始会看到我们动用了一个高级函数decorator.在调用的时候呢,先把hello函数啊传进去,然后呢它返回一个匿名函数。

在这个匿名函数中呢,程序除了运行了自己的代码啊,也调用了被传入的hello函数。

那这个玩法和python异曲同工啊,只不过呢go呢并不支持像python那样的decorator注解于法糖,所以呢在调用上会有些难看。

那当然呢如果想要让代码更容易读一些,你还可以用文中展示的另外一种方法。

我们再来看一段给函数打印执行消耗时间的代码。

那这段代码中呢有两个sum函数,sum一函数呢就是简单的做个循环。

那sum二函数呢动用了数据公式,那代码中呢还使用了购物源的反射机制来获取函数名。

那这里的修饰期函数啊是time的。

Some funk,我们再来看一个HDDP路由的例子。

在这段代码中呢,我们写了多个函数啊,有写HTTP响应头的,有写认证cookie的,有检查认证cookie的,还有打日志的等等。

那在使用过程中呢,我们可以把它们嵌套起来,使用,在修饰过的函数之上继续来修饰。

那这样呢就可以像文中代码这样拼装出更加复杂的功能。

那当然了,如果一层套一层不好看的话,我们还可以使用pipeline的玩法啊,先写一个工具函数,我们来便利并调用各个decorator.那像这样使用的话,你会发现这样的代码是不是更易读了一些。

Pimeline的功能啊也就体现出来了。

不过呢对于go修饰器模式啊,还有一个小问题啊,就是好像无法做到泛型,就像上面那个计算时间的函数一样。

那它的代码耦合了,需要被修饰的函数的接口类型啊,无法做到非常通用。

那如果这个事儿解决不了,那么这个修日器模式啊还是有点不好用的那因为构语啊它不像python和java,那python呢是动态语言,而java呢有语言虚拟机,所以呢他们可以干许多比较变态的事儿。

然而go语言呢是一个静态的语言,这就意味着它的类型呢需要在编译的时候啊就要搞定啊,否则就无法编译。

不过呢go语言知识的最大的泛型啊是interface,还有比较简单的reflection机制。

在这上面做做文章啊,应该还是可以搞定的那废话不多说,我们来看一看,用reflection机制实现了一个比较通用的修饰器。

为了便于阅读呢,我删除了出错判断代码。

那这段代码呢动用了reflect点,make funk函数啊制作了一个新的函数。

那其中的target fun点call啊调用了被修饰的函数。

那关于构员的反反设制制,我推荐荐官方文章,the loss of reflection.在这里呢我就不不多说了,有兴趣呢你课后打开文中的链接看一看。

那在代码中呢,这个decorator or需要两个参数。

那第一个呢是出参deco PTR啊,就是完成修饰后的函数。

那第二个呢是入参FN啊,就是需要修饰的函数。

那这样写呢是不是有点二啊?的确是不过呢这是我个人啊在购物园里啊,能写出来的最好的代码啊。

如果你知道更加优雅的写法,请你一定要告诉我。

好的,让我们来看一下使用效果。

首先呢假设我们有这样两个需要修饰的函数,然后呢我们就可以这么做。

你会发现使用decorator的时候呢,还需要新生明一个函数签名啊,感觉好傻呀,一点都不泛型,不是吗?谁要这是有类型的静态编译的语言呢?是的,如果你不想声明函数签名呢,在文中啊,我也给你展示了另一种方式,好吧,看上去啊不是那么的漂亮,但是it does work,看样子啊构员目前本身的特性无法做成像java或者python那样。

那对此呢我们只能多求够语啊,多放螳螂。

好了,讲了那么多的例子啊,看了那么多的代码,我估计啊你可能有点晕,让我们来做个小结吧。

通过以上python和go修饰器的例子啊,我们可以看到所谓的修饰器模式啊,其实就是在做这么几件事儿。

首先呢从表面上来看啊,修饰器模式啊就是扩展现有的一个函数的功能,让它可以干一些其他的事儿,或者呢是在现有的函数功能上再附加上一些别的功能。

那其次呢,我们除了可以感受到函数式编程下的代码扩展能力,我们还能感受到函数的互相和随意拼装带来的好处。

但是深入看上去啊,我们不难发现decorator这个函数啊其实是可以修饰几乎所有的函数的。

于是呢这种可以通用于其他函数的编程方式,可以很容易的将一些非业务功能呢啊属于控制类型的代码给抽象出来。

那所谓控制类型的代码,就是像follop打日志函数路由啊,或者是求函数运行时间之类的非业务功能性的代码。

那文末呢是辩程范式游记系列文章的目录啊,方便你了解这一系列内容的全貌。