控制结构(8): 线性化(linearization)
// 上一篇:管道(pipeline)
// 下一篇:程序计数器(PC)
“编程语言不过是一个工具,什么语言都一样”,“编程语言能改变人的思维,不同的语言会带给你不同的思考方式”,这是我学习编程之后经常听到的两种说法。到底哪一种更靠谱呢?这要看说者从什么角度去考虑的。
同样是“编程语言不过是一个工具,什么语言都一样”这句话,不同的人所指的也不一样。有的人用什么语言都只写基本都CRUD代码,那他可能会觉的好像换个语言也没什么差别,所以会觉的用什么语言都一样。有的人并不怎么关心技术内功,只是完成工作,早早有机会就转去做非技术工作,他可能也会觉的编程语言不过是一个工具,对他来说没什么差别。有的人则是用过各种语言,做过各种项目,深刻理解到了不同语言共性的地方,例如在解决很多领域问题的时候,语言的实现上是一回事,但怎样对领域特定问题建模,构架可能是更重要的,实现上的差异此时可能不起决定作用,他可能会说编程语言是个工具。诸如此类,不一而足。
而持“编程语言能改变人的思维,不同的语言会带给你不同的思考方式”的人,也大致有分类。有的人并没有深入理解日常使用的一个编程语言,频繁辗转于学习各种新新语言,每个语言都写写HelloWord,可能觉的不同的语言其实没什么差别,或者好像某个语言只是多了一些不同的关键字,少了一些语言特性等等。这样的时候,会迷失在不同语言的表象之下。而有的人深入理解了日常使用的语言,并用它开发了实际有用的软件、项目、产品等,包括业务系统和核心系统,完整的工程实践让他理解到了很多语言特性的优劣,这些优劣不仅仅局限在“哇,这个语言太牛了,如此的自由表达”这样的“做加法”的理解上,而是包括了“嗯,这个语言的这几个设计让程序开发在整体上倾向于模块化、可维护、避免复杂细节”,以及“嗯,这个语言的这些特性要限制性使用,它们会带来一些状态爆炸以及难以维护的意大利面条”,“这个语言在错误处理上提供了不错的机制,这个机制可以更快发现问题而不是隐藏问题”,等等这样的思考。这样的经过工程实践的理解是另外一种。也有人说不同的编程语言提供了不同的范式:“面向过程、面向对象、函数式”等等,会写function不等于面向过程就学好了,会写class也不等于面向对象就学好了,会写lambda不代表对函数式里的无状态假设就理解到位了。
比如“全局变量是代码不可维护的根源”这点,在不同语言里可能有不同形式的存在:
- 直接使用全局变量+多个全局函数,这些全局函数直接访问全局变量。类似这样:
int g_xxx;
float g_yyy;
void do_something1(){
g_xxx = ...;
}
void do_something2(){
g_yyy = gxxx + ...;
}
...
也许一开始代码很少,可以这样写,但是当项目演化、需求变更,全局变量就各种跳线,会形成意大利面条代码,难以维护。
- 有人说,那我全部装进一个class总可以了吧?此时要避免“万能类”,类似这样:
class Manager{
int g_xxx;
float g_yyy;
void do_something1(){
g_xxx = ...;
}
void do_something2(){
g_yyy = gxxx + ...;
}
//...
void do_something100(){
g_yyy = gxxx + ...;
}
}
在一个class里面塞进了太多的功能,也不分模块,一样是犯了“全局变量”的毛病。即使是有经验的程序员,在面对项目演化,需求变更,BUG修改的时候,也可能会把本来状态简单的一个类改着改着变成一个万能类。因此,在这个过程中要写出真正的只干该干的事情的Object,而不是挂羊头卖狗肉的函数和数据的集合。
- 换一个带有闭包的语言,闭包带来了便利,使得我们不必写非常多的辅助函数和辅助类就可以在一个闭包里完成一堆功能。类似这样:
function dosomething(onDone)
local conext = {
state = ..,
data = ...
}
local function do_something1(onComplete)
context.data = ...
end
local function do_something2(onComplete)
context.state = ...
end
local function do_something2_rec(onComplete)
....
do_something1(function()
do_something2_rec(function()
....
end)
end)
end
.....
do_something2_rec(function()
onDone()
end)
end
在这里,一个闭包里做了递归之后,实际上这些闭包函数+context,构成了一组本来应该一个class做的事情,这样的代码如果不是逻辑清晰和直观的,久而久之就会变的难以维护。一个闭包隐约等价于一个class等构造函数,如果说在class的构造里,我们要注意避免资源的循环引用,那么在闭包里同样是需要的。例如:
function connect()
local connection = createConnection()
connection:OnStateChange(function(conn,oldState,newState)
connection.xxx = ...
end)
end
这里就在OnStateChange里闭包里connection对象自身,只要这个闭包还存活着,connection就不会死掉。所以需要小心的在必要的地方移除注册的闭包。另外一种就是在OnStateChange里不去闭包外部的connection,而是使用函数本身的参数conn。
实际上,当闭包变的复杂,我们可以通过将其重新封装成一个对象来让代码模块化和可维护:
function dosomething(onDone)
let obj = Context:New(...)
obj.run(function()
onDone()
end)
end
重新来看“全局变量”,应该是这样的角度去理解:
全局变量+多个全局函数,等价于在函数内的闭包变量+多个嵌套函数,等价于在写在一个类内部的多个应该被拆分的逻辑子类,都是耦合和不可维护的根源。
而如果从函数式语言的角度来看,函数式语言里提供lambda反而没有这么多毛病,因为函数式语言是无状态的,所以闭包并不会因为状态的组合导致副作用。
从而,我们可以回过头理解下关于函数的“自由变量”:
function test(a,b)
return a+b+d;
end
a和b都是test函数的约束变量(bound variable),而d是test函数的自由变量(free variable)。无论这个函数是在全局的,calss里的、局部的。自由变量导致函数不可重入,有副作用,所以在非函数式语言里写局部函数、匿名函数都应该注意减少自由变量,减少函数的副作用。从这个角度来说,一个闭包可以看成是功能比较强的函数,同时也是一个功能比较弱(模块化,封装性差)的class。
控制结构(8): 线性化(linearization)的更多相关文章
- 控制结构(8) 线性化(linearization)
// 上一篇:管道(pipeline) // 下一篇:程序计数器(PC) "编程语言不过是一个工具,什么语言都一样","编程语言能改变人的思维,不同的语言会带给你不同的思 ...
- 控制结构(7) 程序计数器(PC)
// 上一篇:最近最少使用(LRU) // 下一篇:线性化(linearization) 程序的每一行都是一个状态,对应的行指令.同步的情况下同一个pc一直自增,异步的时候,分裂出一个新的子pc,独立 ...
- Scala入门3(特质线性化)
尝试设计一套特质,灵活的改动整数队列.队列有两种操作:put把整数放入队列,get从尾部取出它们.队列是先进先出的,get应该依照入队列的顺序取数据.提示:可以用mutable.ArrayBuffer ...
- feilong's blog | 目录
每次把新博客的链接分享到技术群里,我常常会附带一句:蚂蚁搬家.事实上也确实如此,坚持1篇1篇的把自己做过.思考过.阅读过.使用过的技术和教育相关的知识.方法.随笔.索引记录下来,并持续去改进它们,希望 ...
- Python’s super() considered super!
如果你没有被Python的super()惊愕过,那么要么是你不了解它的威力,要么就是你不知道如何高效地使用它. 有许多介绍super()的文章,这一篇与其它文章的不同之处在于: 提供了实例 阐述了它的 ...
- 控制结构(9) 管道(pipeline)
// 上一篇:线性化(linearization) // 下一篇:指令序列(opcode) 最近阅读了酷壳上的一篇深度好文:LINUX PID 1 和 SYSTEMD.这篇文章介绍了systemd干掉 ...
- 控制结构(9): 管道(pipeline)
// 上一篇:线性化(linearization) // 下一篇:指令序列(opcode) 最近阅读了酷壳上的一篇深度好文:LINUX PID 1 和 SYSTEMD.这篇文章介绍了systemd干掉 ...
- 控制结构(2) 卫语句(guard clause)
// 上一篇:分枝/叶子(branch/leaf) // 下一篇:状态机(state machine) 基于语言提供的基本控制结构,更好地组织和表达程序,需要良好的控制结构. 典型代码: 同步版本 f ...
- 控制结构(2): 卫语句(guard clause)
// 上一篇:分枝/叶子(branch/leaf) // 下一篇:状态机(state machine) 基于语言提供的基本控制结构,更好地组织和表达程序,需要良好的控制结构. 典型代码: 同步版本 f ...
随机推荐
- 第62章 EntityFramework支持 - Identity Server 4 中文文档(v1.0.0)
为IdentityServer中的配置和操作数据扩展点提供了基于EntityFramework的实现.EntityFramework的使用允许任何EF支持的数据库与此库一起使用. 这个库的仓库位于这里 ...
- MEF 基础简介 三
MEF导出类的方法和属性 首先来说导出属性,因为这个比较简单,和导出类差不多,先来看看代码,主要看我加注释的地方,MusicBook.cs中的代码如下: using System; using Sys ...
- windows安装elasticsearch
1. 去官网 https://www.elastic.co/cn/ 下载 注意: ES对JDK版本有较高的要求,5.x及以上版本需要JDK8支持,本人此次使用2.4.6版本2. 下载后,JDK先安装, ...
- php设计模式--简单介绍
鉴于最近有几个小伙伴总问一些设计模式相关的东西,本人借鉴了一些东西,准备将常见的几种php的设计模式总结整理出来. 平时我们用到的设计模式很多,建议大家多多读一些php开源框架,当深入的阅读了一些ph ...
- TSP(Traveling Salesman Problem)-----浅谈旅行商问题(动态规划,回溯实现)
1.什么是TSP问题 一个售货员必须访问n个城市,这n个城市是一个完全图,售货员需要恰好访问所有城市的一次,并且回到最终的城市. 城市于城市之间有一个旅行费用,售货员希望旅行费用之和最少. 完全图:完 ...
- Django学习之二:Django 项目创建 和 应用创建
Django 项目创建 和 应用创建 创建一个Django项目 都是在相应平台的命令行环境下操作: 1. 进入用于存放项目的目录下 1.1 windows下切换目录:先进入具体的分区磁盘中如E盘就输入 ...
- Web 性能优化: 图片优化让网站大小减少 62%
摘要: 压缩各种格式的图片. 原文:Web 性能优化: 图片优化让网站大小减少 62% 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是 Web 性能优化的第二篇,上一篇在下面看点 ...
- vuex2中使用mapGetters/mapActions报错解决方法
解决方案 可以安装整个stage2的预置器或者安装 Object Rest Operator 的babel插件 babel-plugin-transform-object-rest-spread . ...
- 下载Dynamics 365 Customer Engagement 工具
微软动态CRM专家罗勇 ,回复312或者20190311可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . 从Dynamics ...
- Dynamics 365中自定义工作流活动获取的上下文分析及注意事项
关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复244或者20170306可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...