编程范式 | 青训营笔记

130 阅读13分钟

语言介绍

1.机器语言

  机器语言是一种计算机能够直接理解和执行的语言,它是由二进制代码(0和1)组成的,用于控制计算机硬件的操作。机器语言是计算机的底层语言,与高级编程语言相比,机器语言更加底层和基础,具有更高的执行效率。机器语言是计算机系统中最基本的语言,它是由CPU直接执行的指令,通常是由程序员编写的汇编语言程序转换而来。机器语言是计算机操作系统和应用程序的基础,它们都需要通过机器语言的指令来控制计算机硬件的操作。

2.汇编语言

  汇编语言是一种低级编程语言,它是机器语言的一种文本表示形式。与机器语言相比,汇编语言使用更加易于理解和记忆的符号和助记符来代替二进制代码。汇编语言程序需要经过汇编器的处理,将汇编指令翻译成机器指令,才能被计算机执行。

  汇编语言与机器语言密切相关,汇编语言程序直接转换成机器语言指令,因此执行效率非常高。汇编语言程序通常用于编写底层系统软件、设备驱动程序和实时嵌入式系统等需要高效执行的应用。但是,由于汇编语言的语法较为简单,可读性和可维护性较差,因此在编写大型应用程序时很少使用汇编语言。

3.高级语言

  高级语言是一种计算机编程语言,它比机器语言和汇编语言更加抽象和易于理解。高级语言使用类似于自然语言的语法和结构,可以更加直观地描述计算机程序的逻辑和功能。高级语言程序需要经过编译器或解释器的处理,将高级语言代码转换成机器语言指令,才能被计算机执行。

  高级语言与机器语言和汇编语言相比,具有更高的可读性、可维护性和可移植性,可以更加容易地编写和维护大型应用程序。高级语言还提供了许多高级的编程特性,例如面向对象编程、泛型编程、异常处理等,使得程序员可以更加高效地编写复杂的应用程序。常见的高级语言包括Java、Python、C++、C#、JavaScript等。

编程范式

  编程范式是一种编程风格或编程思想,它描述了程序员如何组织和设计计算机程序。不同的编程范式有不同的规则、原则和概念,它们影响了程序员如何思考问题、如何组织代码、如何处理数据等方面。常见的编程范式包括:

  1. 面向过程编程(Procedural Programming):以过程为中心,将程序分解成若干个小的子过程,每个子过程完成一个特定的任务。代表性语言是C语言
  2. 面向对象编程(Object-Oriented Programming):以对象为中心,将程序分解成若干个对象,每个对象包含数据和方法,通过方法来操作数据。代表性语言是C++
  3. 函数式编程(Functional Programming):将程序视为数学函数的组合,强调函数的纯粹性和不可变性,避免使用共享状态和可变数据。代表性语言是Lisp
  4. 响应式编程(Reactive Programming):它强调数据流的响应式和异步编程模型。在响应式编程中,程序会对数据流进行订阅(Subscribe)和推送(Push),当数据流发生变化时,程序会自动触发相应的操作。

编程范式图.png 下面我们来具体了解一下各种编程范式:

1.面向过程

  面向过程编程以过程为中心,将程序分解成若干个小的子过程,每个子过程完成一个特定的任务。在面向过程编程中,程序员需要关注程序的执行顺序和每个过程的输入和输出,从而实现程序的功能。这种编程范式的特点是自顶向下和结构化编程:
(1)自顶向下:面向过程的编程把程序自上而下分为许多个模块,每个模块里面又包含了许多的变量和函数,变量里面又包含了数据结构,函数里面又可以包含函数和语句,可以用下图来表示:

自顶向下.png

(2)结构化编程:程序通常会被分为三大结构:顺序结构、选择结构、循环结构
顺序结构指的是程序按照顺序,自上而下的执行;选择结构指的是程序遇到分支时,会按照条件判断结果选择其中的一个分支执行;循环结构指的是程序进入到循环语句时会重复执行循环语句

结构化编程.png

结构化编程.png

  但是面向过程的编程存在以下缺点:数据与算法关联弱、不利于修改和扩充、不利于代码重用。为了解决这些问题,出现了面向对象的编程。

2.面向对象

  面向对象编程以对象为中心,将程序分解成若干个对象,每个对象包含数据和方法,通过方法来操作数据。在面向对象编程中,程序员将程序视为一组相互作用的对象,每个对象都有自己的状态和行为。它的核心概念包括以下几点:

  1. 类(Class):类是对象的模板,它定义了对象的属性和方法。
  2. 对象(Object):对象是类的实例,它包含了类定义的属性和方法。
  3. 封装(Encapsulation):封装是指将对象的属性和方法封装起来,只对外部暴露必要的接口,隐藏内部实现细节。
  4. 继承(Inheritance):继承是指在已有类的基础上,创建一个新的类,新类具有原有类的属性和方法。
  5. 多态(Polymorphism):多态是指同样的方法可以在不同的对象上产生不同的行为,提高了代码的可重用性和灵活性。

  同时,面向对象还有五大原则:

  1. 单一职责原则(Single Responsibility Principle,SRP):一个类应该只有一个职责,即只负责一个功能领域中的相应职责。这样可以使类更加内聚,降低类之间的耦合度。
  2. 开放封闭原则(Open-Closed Principle,OCP):一个类应该对扩展开放,对修改关闭。这意味着在不修改现有代码的情况下,可以通过扩展类的行为来满足新的需求。
  3. 里氏替换原则(Liskov Substitution Principle,LSP):子类应该可以替换掉父类并且不会影响程序的正确性。这意味着子类应该保留父类的行为,并且不能修改父类的行为。
  4. 接口隔离原则(Interface Segregation Principle,ISP):一个类不应该强制客户端依赖它们不需要的方法。这意味着接口应该尽可能小,类只需要实现它们需要的接口。
  5. 依赖倒置原则(Dependency Inversion Principle,DIP):高层模块不应该依赖低层模块,它们应该都依赖于抽象接口。这意味着抽象接口应该定义在高层模块中,具体实现应该定义在低层模块中,从而实现高层模块和低层模块之间的解耦。

  面向对象在JS当中有许多体现,比如JS对数组对象的封装实现的很好,许多涉及到数组的操作如追加元素、删除元素等都已经有内置方法,我们只需调用这些方法即可,不必像C语言一样需要我们自己去实现增加、删除元素的函数

  虽然面向对象编程相较于面向过程有许多提高,但是它仍然存在一个问题:面向对象的编程总是附带着所有它需要的环境。引用Erlang的创始人joe Armstrong的话来说就是:“你想要一根香蕉,但得到的却是一个大猩猩拿着香蕉,而且还有整片丛林。”为了解决这个问题,出现了函数式编程。

3.函数式编程

  函数式编程强调函数的纯粹性和不可变性,避免使用共享状态和可变数据。在函数式编程中,函数被看作是一种数学函数,输入和输出之间没有任何副作用,同样的输入会得到同样的输出。

  函数式编程的核心概念包括:

  1. 纯函数(Pure Function):纯函数是指输入和输出之间没有任何副作用,同样的输入会得到同样的输出。
  2. 不可变性(Immutability):不可变性是指数据不可被修改,任何修改操作都会返回一个新的数据结构。
  3. 高阶函数(Higher-Order Function):高阶函数是指函数可以作为参数传递和返回值。
  4. 递归(Recursion):递归是指函数可以调用自身。

  函数式编程可以应用于各种场景,例如前端开发、后端开发、大数据处理等。常见的函数式编程语言包括Haskell、Lisp、Clojure、Scala等。函数式编程具有以下优点:

  1. 可读性高:函数式编程强调函数之间的组合和管道操作,代码更加简洁、清晰、易于理解。
  2. 可维护性好:函数式编程避免了共享状态和可变数据,减少了代码的副作用,使得代码更加易于维护和调试。
  3. 可扩展性强:函数式编程强调高阶函数和递归,使得代码更加灵活、可扩展、可重用。
  4. 并发性强:函数式编程避免了共享状态和可变数据,使得并发编程更加容易和安全。

4.响应式编程

  响应式编程(Reactive Programming)是一种面向数据流和变化传播的编程范式,它通过使用异步数据流来处理事件和数据,从而实现高效的数据处理和响应。在响应式编程中,数据流被看作是一个不断变化的流,程序需要对数据流进行监听和处理,以便及时响应数据的变化。

  响应式编程的核心思想是基于观察者模式和迭代器模式,通过定义数据流和事件流,实现数据的异步处理和响应。在响应式编程中,数据流可以是任何类型的数据,包括用户输入、网络请求、传感器数据等等。程序需要对这些数据流进行监听和处理,以便及时响应数据的变化。

  响应式编程的优点包括:

  1. 响应式编程能够处理异步事件和数据流,使得程序能够更加高效地处理数据和事件,同时减少了对线程和锁的依赖。
  2. 响应式编程能够处理复杂的事件和数据流,使得程序能够更加容易地处理复杂的业务逻辑和数据处理任务。
  3. 响应式编程能够提高程序的可靠性和可维护性,因为它能够减少代码中的副作用和状态变化,从而减少了程序的错误和调试难度。
  4. 响应式编程能够提高程序的可扩展性和可重用性,因为它能够将代码分解为独立的组件和模块,从而使得程序能够更加容易地进行扩展和重用。
  5. 响应式编程能够提高程序的性能和效率,因为它能够利用多核处理器和异步IO等技术,从而实现更加高效的数据处理和计算。

领域特定语言(DSL)

  DSL是Domain-Specific Language的缩写,即领域特定语言。它是一种专门为某个特定领域设计的编程语言,用于解决某个特定领域的问题。与通用编程语言相比,DSL更加侧重于解决特定领域的问题,具有更高的表达力和更好的可读性。它具有如下的优点:  

  1. 提高代码可读性和可维护性。DSL是一种针对特定领域设计的语言,因此它的语法和语义更加符合领域的特点,使得代码更加易于理解和维护。
  2. 提高开发效率。DSL能够提供更加高级的抽象和更加简洁的语法,使得开发人员能够更加快速地实现特定领域的功能。
  3. 降低出错率。由于DSL是针对特定领域设计的语言,因此它能够提供更加严格的类型检查和更加规范的语法,从而降低出错率。
  4. 提高代码重用性。由于DSL是针对特定领域设计的语言,因此它能够提供更加通用的函数或类库,使得这些函数或类库能够在不同的项目中被重用。
  5. 提高代码的可扩展性。由于DSL是针对特定领域设计的语言,因此它能够更加容易地扩展和修改,从而适应不同的需求。

  接下来我们了解一下语言的运行,这个过程可以用下图的来表示:

1.png

  1. Lexer:Lexer又称词法分析器,是将输入的源代码转换成一系列Token的工具。Token是编程语言中的最小语法单元,例如关键字、标识符、操作符、常量等。Lexer将源代码分解成一系列Token,然后将Token传递给后续的Parser进行语法分析。
  2. Parser:Parser又称语法分析器,是将一系列Token转换成抽象语法树(AST)的工具。AST是编程语言中表示程序结构的一种数据结构,它是以树形结构组织的,每个节点表示程序的一个语法结构。Parser将Token按照语法规则组织成AST,然后将AST传递给后续的Visit进行语义分析和代码生成。
  3. Visit:Visit是对AST进行遍历和操作的过程。Visit会对AST进行遍历,然后根据语义规则进行分析和操作,最终生成目标代码。Visit通常包括类型检查、符号表处理、优化和代码生成等过程。

  Lexer、Parser和Visit是编程语言解析和代码生成过程中的重要组成部分。Lexer将源代码转换成一系列Token,Parser将Token转换成AST,Visit对AST进行遍历和操作,最终生成目标代码。这些过程都需要严格遵守编程语言的语法和语义规则,以确保程序的正确性和可靠性。