再谈编程范式—程序语言背后的思想

编程范式

托马斯.库尔提出“科学的革命”的范式论后,Robert Floyd在1979年图灵奖的颁奖演说中使用了编程范式一词。编程范式通常包括三个方面,以OOP为例:html

  1,学科的逻辑体系——规则范式:如 类/对象、继承、动态绑定、方法改写、对象替换等等机制。git

  2,心理认知因素——心理范式:按照面向对象编程之父Alan Kay的观点,“计算就是模拟”。OO范式极其重视隐喻(metaphor)的价值,经过拟人化,按照天然的方式模拟天然。程序员

  3,天然观/世界观——观念范式:强调程序的组织技术,视程序为松散耦合的对象/类的组合,以继承机制将类组织成一个层次结构,把程序运行视为相互服务的对象之间的对话。github

简单来讲,编程范式是程序员看待程序应该具备的观点表明了程序设计者认为程序应该如何被构建和执行的见解web

常见的编程范式有:命令式、过程式、说明式、面向对象、函数式、泛型编程等。算法

Imperative—命令式||过程式

  冯诺依曼 机器语言、汇编语言 BASIC COBOL C Ada FORTRAN Fortran ,sql

  脚本式 Perl Python PHP,把用其余语言开发的独立程序做为部件“粘到一块儿”数据库

  面向对象 Smalltalk C++ Java,将计算创建在独立的对象的相互做用至上。每一个对象有其自身的内部状态,以及管理自身状态的可执行子程序express

Declarative—说明式||声明式

  函数式  Lisp ML Haskell ,程序被看做是一种从输入到输出的函数编程

  数据流  ld Val,语言将计算当作在一些基本的功能结点之间流动的信息流。结点由输入单词的到达触发,可以并发操做

  逻辑式  Prolog,设法根据一集逻辑规则找出知足某些特定关系的值

  基于模板的 XSLT xml html,

须要提醒的是:编程范式是编程语言的一种分类方式,它并不针对某种编程语言。就编程语言而言,一种语言能够适用多种编程范式。

 

一些编程语言是专门为某种特定范式设计的,例如C语言是过程式编程语言;Smalltalk和Java是较纯粹的面向对象编程语言;Haskell是纯粹的函数式编程语言。另一些编程语言和编程范式的关系并不一一对应,如Python,Scala,Groovy都支持面向对象和必定程度上的函数式编程。C++是多范式编程语言成功的典范。C++支持和C语言同样的过程式编程范式,同时也支持面向对象编程范式,STL(Standard Template Library)使C++具备了泛型编程能力。支持多种范式多是C++直到如今仍然具备强大的生命力的缘由之一。

Swift是一门典型的多范式编程语言,即支持面向对象编程范式,也支持函数式编程范式,同时还支持泛型编程。Swift支持多种编程范式是由其创造目标决定的。Swift创造的初衷就是提供一门实用的工业语言。不一样于Haskell这类出自大学和研究机构的学术性质的编程语言。苹果推出Swift时就带着着明确的商业目的:Mac OS和iOS系统的主要编程语言Objective-C已显老态,Swift将使得苹果系统的开发者拥有一门更现代的编程语言,从而促进苹果整个生态圈的良性发展。

命令式编程:

命令式编程的主要思想是关注计算机执行的步骤,即一步一步告诉计算机先作什么再作什么

从本质上讲,它是“冯.诺依曼机”运行机制的抽象,它的编程思想方式源于计算机指令的顺序排列。

(也就是说:过程化语言模拟的是计算机机器的系统构造,而并非基于语言的使用者的我的能力和倾向。这一点咱们应该都很清楚,好比咱们最先曾经使用过的单片机的汇编语言。)

无论你用的是 C, C++ 仍是 C#, Java, Javascript, BASIC, Python, Ruby 等等,你均可以以这个方式写。

程序流程图是命令式语言进行程序编写的有效辅助手段

命令式语言特别适合解决线性(或者说循序渐进)的算法问题。它强调“自上而下(自顶向下)”“精益求精”的设计方式。这种方式很是相似咱们的工做和生活方式,由于咱们的平常活动都是循序渐进的顺序进行的。 

命令式语言趋向于开发运行较快且对系统资源利用率较高的程序。命令式语言很是的灵活并强大,同时有许多经典应用范例,这使得程序员能够用它来解决多种问题。 

命令式语言的不足之处就是它不适合某些种类问题的解决,例如那些非结构化的具备复杂算法的问题。问题出如今,命令式语言必须对一个算法加以详尽的说明,而且其中还要包括执行这些指令或语句的顺序。实际上,给那些非结构化的具备复杂算法的问题给出详尽的算法是极其困难的。 

普遍引发争议和讨论的地方是:无条件分支,或goto语句,它是大多数过程式编程语言的组成部分,反对者声称:goto语句可能被无限地滥用;它给程序设计提供了制造混 乱的机会。目前达成的共识是将它保留在大多数语言中,对于它所具备的危险性,应该经过程序设计的规定将其最小化。 

命令式对实际事物处理通常能够拆分为如下两种模式:

  • 流程驱动:相似 通常就是主动轮询 在干活中还要分心 主动去找活干  这样有空余的时间也彻底浪费掉了

    采用警觉式者主动去轮询 ( polling),行为取决于自身的观察判断,是流程驱动的,符合常规的流程驱动式编程 ( Flow-Driven Programming)的模式。

  • 事件驱动:相似  好比公司有一个oa系统 你干完活的时候只须要看下oa系统有没分配给你活 没有能够干本身的事  不用担忧还有其余事没干完

    采用托付式者被动等通知 (notification),行为取决于外来的突发事件,是事件驱动 的,符合事件驱动式编程 ( Event-Driven Programming,简称 EDP)的模式。

 

事件驱动编程

其实,基于事件驱动的程序设计在图形用户界面(GUI)出现好久前就已经被应用于程序设计中,但是只有当图形用户界面普遍流行时,它才逐渐形演变为一种普遍使用的程序设计模式。 

在过程式的程序设计中,代码自己就给出了程序执行的顺序,尽管执行顺序可能会受到程序输入数据的影响。

在事件驱动的程序设计中,程序中的许多部分可能在彻底不可预料的时刻被执行。每每这些程序的执行是由用户与正在执行的程序的互动激发所致。 

  • 事件:就是通知某个特定的事情已经发生(事件发生具备随机性)。 

  • 事件与轮询:轮询的行为是不断地观察和判断,是一种无休止的行为方式。而事件是静静地等待事情的发生。事实上,在Windows出现以前,采用鼠标输入字符模式的PC应用程序必须进行串行轮询,并以这种方式来查询和响应不一样的用户操作。 

  • 事件处理器:是对事件作出响应时所执行的一段程序代码。事件处理器使得程序可以对于用户的行为作出反映。 

事件驱动经常用于用户与程序的交互,经过图形用户接口(鼠标、键盘、触摸板)进行交互式的互动。固然,也能够用于异常的处理和响应用户自定义的事件等等。

事件的异常处理比用户交互更复杂。 

事件驱动不只仅局限在GUI编程应用。可是实现事件驱动咱们还须要考虑更多的实际问题,如:事件定义事件触发、事件转化事件合并事件排队事件分派事件处理事件连带等等。

其实,到目前为止,咱们尚未找到有关纯事件驱动编程的语言和相似的开发环境。全部关于事件驱动的资料都是基于GUI事件的。 

属于事件驱动的编程语言有:VB、C#、Java(Java Swing的GUI)等。它们所涉及的事件绝大多数都是GUI事件。 

此种程化范式要求程序员用循序渐进的算法看待每一个问题。很显然,并非每一个问题都适合这种过程化的思惟方式。这也就致使了其它程序设计范式出现,包括咱们如今介绍的面向对象的程序设计范式。 

 

从编程的发展史来谈面向对象的出现。当软件还很是简单的时候,咱们只须要面向过程编程:

定义函数

函数一 函数二 函数三 函数四

定义数据

数据一 数据二 数据三 数据四

最后各类函数,数据的操做。

当软件发展起来后,咱们的软件变得愈来愈大,代码量愈来愈多,复杂度远超Hello World的时候,咱们的编写就有麻烦了:函数和数据会定义得很是多,面临两个问题。首先是命名冲突,英文单词也就那么几个,可能写着写着取名时就没合适的短词用了,为了不冲突,只能把函数名取得愈来愈长。而后是代码重复,咱们能够用函数里面调用函数的方法,可是函数调函数(好比一个功能多个方法(函数),几个功能混用方法)不便于维护。

 

面向对象程序

面向对象程序设计(Object-oriented programming OOP)是种经过类、方法、对象和消息传递,来支持面向对象的程序设计范式。对象则指的是类的实例。它将对象做为程序的基本单元,将程序和数据封装其中,以提升软件的重用性、灵活性和扩展性,对象里的程序能够访问及常常修改对象相关连的数据。在面向对象程序编程里,程序会被设计成彼此相关的对象

面向对象程序设计能够看做一种在程序中包含各类独立而又互相调用的对象的思想,这与传统的思想恰好相反:传统的程序设计主张将程序看做一系列函数的集合,或者直接就是一系列对计算机下达的指令。面向对象程序设计中的每个对象都应该可以接受数据、处理数据并将数据传达给其它对象,所以它们均可以被看做一个小型的“机器”,即对象。即把事情交给最适合的对象去作

面向对象和面向过程的区别最直观的比喻就如:摇(狗尾巴)和 狗.摇尾巴()的区别。

面向对象编程的三个基本概念:

  • 封装,面向对象程序设计隐藏了某一方法的具体执行步骤,取而代之的是经过消息传递机制传送消息给它。通过深刻的思考,作出良好的抽象,给出“完整且最小”的接口,并使得内部细节能够对外隐藏

  • 继承,在某种状况下,一个类会有“子类”。子类比本来的类(称为父类)要更加具体化;

  • 多态,指由继承而产生的相关的不一样的类,其对象对同一消息会作出不一样的响应;

使用面向对象编程语言,易于构建软件模型。由于,对象很相似乎很容易和现实世界上的全部事物和概念。

面向对象经过接口

  • 类,类是类似对象的集合。物以类聚——就是说明。每一个对象都是其类中的一个实体。类中的对象能够接受相同的消息。换句话说:类包含和描述了“具备共同特性(数据元素)和共同行为(功能)”的一组对象。

  • 接口,每一个对象都有接口。接口不是类,而是对符合接口需求的类所做的一套规范。接口说明类应该作什么但不指定如何做的方法。一个类能够有一个或多个接口。 

  • 方法,方法决定了某个对象究竟可以接受什么样的消息。面向对象的设计有时也会简单地概括为“将消息发送给对象”。 

 

面向对象技术一方面借鉴了哲学、心理学、生物学的思考方式,另外一方面,它是创建在其余编程技术之上的,是之前的编程思想的天然产物。

若是说结构化软件设计是将函数式编程技术应用到命令式语言中进行程序设计,面向对象编程不过是将函数式模型应用到命令式程序中的另外一途径,此时,模块进步为对象,过程龟缩到class的成员方法中。OOP的不少技术——抽象数据类型、信息隐藏、接口与实现分离、对象生成功能、消息传递机制等等,不少东西就是结构化软件设计所拥有的、或者在其余编程语言中单独出现。但只有在面向对象语言中,他们才共同出现,以一种独特的合做方式互相协做、互相补充。

 

从上面能够看到,若是按照面向过程的方法去设计汽车,汽车厂商须要采购一大堆零件,而后研究如何调试、调用这一大堆零件以完成一个功能。可是若是采用面向对象的方法去设计汽车,那么汽车厂商能够采用外包的方式交给专业的制动系统厂商来设计,只须要约定须要开放哪些public方法,输入什么输出什么就能够了。

 

在知乎kevin zou总结的三种面向对象方式:

静态函数包对象

将功能有联系的一批函数放在一块儿封装成一个类。这种类能够彻底没有内部数据,也能够有数据。当有数据时,这些数据充当的其实就是配置(配置对于一个设计优秀的对象,是透明的,对象自己内部的函数根本不知道有配置这个东西,它只知道它须要的每个数据在它new以后就已经存在this里了,随取随用。配置的给予或获取方式,是构建对象(new)时才须要去考虑的)这种对象的特色是,它的每个函数(或方法)对这些数据都是只读的,因此无论方法有无被调用,被谁调用,被调用多少次,它也不会改变它的状态。

领域模型对象

这个概念是相对于传统的面向数据库的系统分析和设计而言的。数据库虽然只用了外键就描述了复杂的大千世界,但软件开发的难点在于适应变化,而且可以安全地修改。关系模型看似简单,但它却像一张蜘蛛网同样将全部table和栏位包在一块,牵一发而动全身,让你在修改时如履薄冰,一不当心就会顾此失彼,bug此起彼伏。而OO的封装特性则恰好能够用来解决这个问题。将业务数据整理成一个个独立的对象,让它们的数据只能被本身访问。留给外界的基本上只是一些接口(方法),数据除非万不得已,一个都不会公开。外界只能向它发送消息,它本身则经过修改自身数据来响应这种消息。这种对象与第一种对象恰好相反,它必定有数据,并且它的每个函数存在的目的就是修改本身的数据。且每一次修改都是粗粒度的,每一次修改后,对象也仍是处在valid状态。推荐阅读《领域模型浅析》,《领域模型,你真的理解的了吗?

顺便拓展下:领域驱动设计(Domain-Driven Design)-贫血模型-领域模型-充血模型

临时对象

其它用来解决过程式开发时,超多的变量,超复杂的流程而整理出来的小对象,。这些对象一块儿协做,最后完成一个传统成千上万行的过程式代码才能完成的功能。例如如今要链接sql server执行查询语句并取得结果返回。不使用任何类库和工具,全部步骤都本身进行,例如解析协议,socket网络链接,数据包收发等。这时候从头至尾用一个个函数来完成,绝对没有先划分出一个个职责分明的对象,让各对象协做完成这件事情来得更简单。

 

但编程实践代表,并非任何东西成为对象都是一件好事情。举一个Java中的蹩足的例子:Java中只有对象才能做为参数传入函数(固然还有原始类型primitive type)。因此为了将函数传递给另一个函数,你须要将函数包裹在一个对象中,一般会用一个匿名类,由于这个类不会有其余做用,只是为了让Java的一切皆为对象的设计高兴。

Java拥有纯粹的面向对象概念。它从设计之初,就但愿以一切皆为对象的纯对象模型来为世界建模。但发展到如今,Java中加入了愈来愈多非对象的东西。引入了闭包,从而得到了函数式编程中的一级函数;引入泛型,从而得到了参数化的类型。这可能暗示了,这个世界是如此得丰富多彩,使用单一模式为世界建模并不会成功。

 

声明式编程:

声明式编程是以数据结构的形式来表达程序执行的逻辑。它的主要思想是告诉计算机应该作什么,但不指定具体要怎么作

SQL 语句就是最明显的一种声明式编程的例子,例如:

SELECT * FROM collection WHERE num > 5

除了 SQL,网页编程中用到的 HTML 和 CSS 也都属于声明式编程。

经过观察声明式编程的代码咱们能够发现它有一个特色是它不须要建立变量用来存储数据

另外一个特色是它不包含循环控制的代码如 for, while

函数式编程和声明式编程是有所关联的,由于他们思想是一致的:即只关注作什么而不是怎么作。但函数式编程不只仅局限于声明式编程。

函数式编程

函数式编程(functional programming)或称函数程序设计、泛函编程,是一种编程范式,它将计算机运算视为函数运算,而且避免使用程序状态以及易变对象。其中,λ演算(lambda calculus)为该语言最重要的基础。并且,λ演算的函数能够接受函数看成输入(引数)和输出(传出值)。

函数式编程关心类型(代数结构)之间的关系,命令式编程关心解决问题的步骤。函数式编程中的lambda能够当作是两个类型之间的关系,一个输入类型和一个输出类型。lambda演算就是给lambda表达式一个输入类型的值,则能够获得一个输出类型的值,这是一个计算,计算过程知足  -等价和  -规约。函数式编程的思惟就是如何将这个关系组合起来,用数学的构造主义将其构造出你设计的程序

比起命令式编程,函数式编程更增强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。

 

命令式编程是面向计算机硬件的抽象,有变量(对应着存储单元),赋值语句(获取,存储指令),表达式(内存引用和算术运算)和控制语句(跳转指令),一句话,命令式程序就是一个冯诺依曼机的指令序列。

函数式编程是面向数学的抽象,将计算描述为一种表达式求值,一句话,函数式程序就是一个表达式。

函数式编程最重要的特色是“函数第一位”,即函数能够出如今任何地方,好比你能够把函数做为参数传递给另外一个函数,不只如此你还能够将函数做为返回值。

函数式编程的本质

函数式编程中的函数这个术语不是指计算机中的函数(其实是Subroutine),而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其余状态。好比sqrt(x)函数计算x的平方根,只要x不变,不论何时调用,调用几回,值都是不变的。

在函数式语言中,函数做为一等公民,能够在任何地方定义,在函数内或函数外,能够做为函数的参数和返回值,能够对函数进行组合。

纯函数式编程语言中的变量也不是命令式编程语言中的变量,即存储状态的单元,而是代数中的变量,即一个值的名称变量的值是不可变的(immutable),也就是说不容许像命令式编程语言中那样屡次给一个变量赋值。好比说在命令式编程语言咱们写“x = x + 1”,这依赖可变状态的事实,拿给程序员看说是对的,但拿给数学家看,却被认为这个等式为假。

函数式语言的如条件语句,循环语句也不是命令式编程语言中的控制语句,而是函数的语法糖,好比在Scala语言中,if else不是语句而是三元运算符,是有返回值的。

严格意义上的函数式编程意味着不使用可变的变量,赋值,循环和其余命令式控制结构进行编程。

从理论上说,函数式语言也不是经过冯诺伊曼体系结构的机器上运行的,而是经过λ演算来运行的,就是经过变量替换的方式进行,变量替换为其值或表达式,函数也替换为其表达式,并根据运算符进行计算。λ演算是图灵彻底(Turing completeness)的,可是大多数状况,函数式程序仍是被编译成(冯诺依曼机的)机器语言的指令执行的。

 

 

函数式编程的特性

  • 函数是"一等公民":函数优先,和其余数据类型同样。

  • 只用"表达式",不用"语句":经过表达式(expression)计算过程获得一个返回值,而不是经过一个语句(statement)修改某一个状态。

  • 无反作用:不污染变量,同一个输入永远获得同一个数据。

  • 不可变性:前面一提到,不修改变量,返回一个新的值。

因为变量值是不可变的,对于值的操做并非修改原来的值,而是修改新产生的值,原来的值保持不便。

一般来讲,算法都有递推(iterative)递归(recursive两种定义。

 

因为变量不可变,纯函数编程语言没法实现循环,这是由于For循环使用可变的状态做为计数器,而While循环DoWhile循环须要可变的状态做为跳出循环的条件。所以在函数式语言里就只能使用递归来解决迭代问题,这使得函数式编程严重依赖递归。

函数式语言固然还少不了如下特性:
  • 高阶函数(Higher-order function):就是参数为函数或返回值为函数的函数。有了高阶函数,就能够将复用的粒度下降到函数级别,相对于面向对象语言,复用的粒度更低。

  • 偏应用函数(Partially Applied Functions):一个函数接收一个有多个参数的函数,返回一个须要较少参数的函数。偏函数将一到多个参数在内部固定,而后返回新函数,返回的函数接收剩余的参数完成函数的应用。

  • 柯里化(Currying):输入一个有多个参数的函数, 返回一个只接收单个参数的函数。

  • 闭包(Closure):闭包就是有权访问另外一个函数做用域中变量的函数.闭包的三个特性:1.闭包是定义在函数中的函数 。2.闭包能访问包含函数的变量。3.即便包含函数执行完了, 被闭包引用的变量也得不到释放。具体参看《闲话闭包

 

函数式编程的好处 

因为命令式编程语言也能够经过相似函数指针的方式来实现高阶函数,函数式的最主要的好处主要是不可变性带来的。没有可变的状态,函数就是引用透明(Referential transparency)的和没有反作用(No Side Effect

函数即不依赖外部的状态也不修改外部的状态,函数调用的结果不依赖调用的时间和位置,这样写的代码容易进行推理,不容易出错。这使得单元测试和调试都更容易。

因为(多个线程之间)不共享状态,不会形成资源争用(Race condition),也就不须要用来保护可变状态,也就不会出现死锁,这样能够更好地并发起来,尤为是在对称多处理器(SMP)架构下可以更好地利用多个处理器(核)提供的并行处理能力。

我以为函数编程的好处就不用管js里面该死的this指向

函数式编程语言还提供惰性求值-Lazy evaluation,也称做call-by-need,是在将表达式赋值给变量(或称做绑定)时并不计算表达式的值,而在变量第一次被使用时才进行计算。这样就能够经过避免没必要要的求值提高性能。

函数式编程语言通常还提供强大的模式匹配(Pattern Match)功能。在函数式编程语言中能够定义代数数据类型(Algebraic data type),经过组合已有的数据类型造成新的数据类型,如在Scala中提供case class,代数数据类型的值能够经过模式匹配进行分析。

函数式编程天生亲和单元测(特别是黑盒测试),由于FP关注就是输入与输出。反观Java或者C++,仅仅检查函数的返回值是不够的:代码可能修改外部状态值,所以咱们还须要验证这些外部的状态值的正确性。在FP语言中呢,就彻底不须要。

调试查错方面,由于FP程序中的错误不依赖于以前运行过的不相关的代码。而在一个指令式程序中,一个bug可能有时能重现而有些时候又不能。由于这些函数的运行依赖于某些外部状态, 而这些外部状态又须要由某些与这个bug彻底不相关的代码经过某个特别的执行流程才能修改。在FP中这种状况彻底不存在:若是一个函数的返回值出错了,它一直都会出错,不管你以前运行了什么代码。而整个程序就是函数接龙。

推荐阅读《傻瓜函数式编程

泛型编程

泛型编程是另一个有趣的话题。泛型为程语言提供了更高层级的抽象,即参数化类型。换句话说,就是把一个本来特定于某个类型的算法或类当中的类型信息抽象出来。这个抽象出来的概念在C++的STL(Standard Template Library)中就是模版(Template)。STL展现了泛型编程的强大之处,一出现就成为了C++的强大武器。除C++以外,C#,Java,Haskell等编程语言都引入了泛型概念。

 

泛型编程是一个稍微局部一些的概念,它仅仅涉及如何更抽象地处理类型,即参数化类型。这并不足以支撑起一门语言的核心概念。咱们不会听到一个编程语言是纯泛型编程的,而没有其余编程范式。但正由于泛型并不会改变程序语言的核心,因此在大多数时候,它能够很好的融入到其余的编程方式中。C++,Scala,Haskell这些风格迥异的编程语言都支持泛型。泛型编程提供了更高的抽象层次,这意味着更强的表达能力。这对大部分编程语言来讲都是一道美味佐餐美酒。

 

在Swift中,泛型获得普遍使用,许多Swift标准库是经过泛型代码构建出来的。例如Swift的数组和字典类型都是泛型集。这样的例子在Swift中随处可见。

 

参考文章:

编程范式[ 程序员的编程世界观 ]

汉诺塔——各类编程范式的解决 

编程范式:命令式编程(Imperative)、声明式编程(Declarative)和函数式编程(Functional)

神奇的λ演算 https://www.cnblogs.com/dragonpig/archive/2010/01/26/1657052.html

编程语言范式 http://www.cnblogs.com/lisperl/archive/2011/11/20/2256165.html 

λ 演算学习 http://www.javashuo.com/article/p-fttrfqid-hh.html

函数式编程漫谈 https://cloud.tencent.com/developer/article/1190773

此文大可能是本文给出的连接文字提炼总结,若是不妥之处,请到本站留言,告知,拜谢!

相关文章
相关标签/搜索