Q: 什么是食物?
A: 食物通常以碳水化合物、脂肪、蛋白质或水构成,能够借由进食或是饮用为人类或者生物提供营养或愉悦的物质。
食物的来源可以是植物、动物或者其他界的生物,例如真菌,亦或发酵产品像是酒精。
生物摄取食物后,被生物的细胞同化,提供能量,维持生命及刺激成长。
前段时间讨论到Java中的回调函数时,提到了面向切面(Aspect Oriented Programming)编程。它是一种程序设计思维,常常与面向对象(Object Oriented Programming)编程相比较,但是也常常被单独拎出来讨论。
OOP的诞生源自于人类与生俱来的分类抽象能力,回想一下,读小学的你,是否就能轻而易举地分辨“零食”和“正餐”的区别呢?零食美味而充满诱惑,但是对于你来说昂贵,而且吃太多存在挨骂的风险,相对的,正餐则略显的无聊和平淡,但是在你饿了的时候往往能让你的肚子不会咕咕叫。
于是自然而然你就可以将它们的共同点抽象出来,比如它们可以被食用,但是它们的味道、价格、食用时间乃至“副作用”之类的都不太一样。它们中相同的属性,就可以分配给一个只对这些相同的属性敏感的父元素。而不同的部分,就单独分配给父元素下属的不同的子元素。这样一来,子元素就不光含有自己的属性,也拥有了父元素的所有属性。
面向切面
事物中对于某些相同属性的抽象,构成了面向对象的基石。
来写一个简单的OOP的例子
1 | // JavaScript ES6 |
侵入式切面
假设我们想要在对象
代理函数是个很好的选择,我们在进行具体的业务调用时,直接调用一个代理函数就行了。
1 |
|
函数
1 | before(ted, ted.design, 'painting some blueprints'); |
上面的全局函数,还可以直接添加进对象中,防止被不必要的类或者方法使用。
1 |
|
虽然这种形式大体上能解决我们的需求,但是这种写法,仍然破坏了对象原有的调用形式。
1 |
|
清一色的
非侵入式切面
代理函数帮我们执行了函数,虽然能按照我们的期望执行程序,但我们更希望它直接返回函数给我们,这样我们就无须费劲心思地去到处修改旧代码,同时往代码中添加了新的功能。
1 |
|
以上代码还可以写成更加通用的写法
1 |
|
程序中那些无法通过父元素所聚合的共同属性,但是又切实地影响到了程序的写作——这种时候,切面编程就能发挥出它的用处。它将业务中的相同的部分抽象出来,组成一个个可拆卸的业务组件。面向对象通过继承和多态的纵轴让代码松耦合,而面向切面则是在业务并行展开的水平线上让代码松耦合。
中间件
提起AOP,总免不了让人想到Java Spring框架中的监听器、拦截器、过滤器。它们是典型的AOP编程思想的结晶——一条正常的程序流,被几个中间件拦截检查。
这启发了我们,在程序设计上的一条新思路:程序暴露出一段执行流,并且给开发者一把剪刀。它们可以随意在允许的范围内剪开程序,并织入想要执行的内容。最后这一段执行流合重新合并起来,收入程序的深处。
简单模拟一个中间件设计
1 |
|