结构化编程一般采用自顶向下的设计方法,开发人员将整个程序结构 映射到不同的子部分中。
Corrado Bohm 和 Guiseppe Jacopini 两位数学家已证明: 只使用三种结构就可以编写任何计算机程序:
- 判断结构
- 顺序结构
- 循环结构
在结构化编程中,程序员会将一个很大部分代码划分为一个个便于理解 的子部分(可以是函数、子程序、方法和代码块等)。 同时,程序应该使用局部变量,通过值传递或者引用传递参数。
过程式编程是一种基于过程调用概念的编程范式。 过程也称为例程(rutinues)、子例程、方法或函数(仅包含一系列要执行的计算步骤)。 任何给定的过程都可以在过程执行期间的任何时候调用,包括由其他过程或其本身调用。 输入通常以参数的形式在语法上指定,输出作为返回值传递。
要被认为是过程式的,编程语言应该通过具有过程的明确概念和定义它的语法来支持 过程式编程。理想情况下,它应该支持参数类型、局部变量、递归过程调用的规范 以及在单独构建的过程结构中使用过程。它还可以支持输入和输出参数的区别。
面向过程编程的特点:
- 遵循自上而下的方法;
- 数据的重要性不如函数;
- 由于函数共享全局数据,因此存在数据脆弱性。;
- 函数操纵全局数据,而不让其他函数知道;
- 大程序被分成小模块;
- 首先设计算法,不关心细节;
任何问题都有自上而下或自下而上两种处理方式。这里举一个简单的例子来说明这个概念, 对一个数组进行排序涉及以下步骤: (a) 比较 (b) 交换。
在最高层,必须制定一种算法,利用上述操作进行排序。算法确定后, 再制定比较和交换算法,然后再执行整个算法。因此,在这种方法中, 一开始就从顶层开始,而不去考虑实施的微小细节。
自下而上的方法正好相反。首先执行较低层次的任务,然后进行整合以提供解决方案。 在这种方法中,较低层次的结构被执行。在这里,先制定交换和比较的算法, 然后再制定整个问题的算法。
在任何情况下,将问题划分为小任务,然后解决每个任务,都能提供解决方案。 因此,必须采用自上而下或自下而上的方法将问题划分为较小的模块,然后加以解决。 在自上而下的方法中,先确定整体结构,然后再确定细节;而在自下而上的方法中, 先确定细节,然后再确定整体结构。
- 在自上而下的模型中,系统的概述被制定出来,而不对其中的任何部分进行详细设计。然后,通过更详细的设计来完善系统的每个部分;
- 每个新的部分都可以再次细化,对其进行更详细的定义,直到整个规范足够详细,可以对模型进行验证;
- 自上而下的方法强调规划和对系统的补充理解。其固有的特点是,至少在系统的某些部分的设计达到足够详细的程度之前,不能开始编码;
- 自顶向下编程是一种编程风格,是传统过程式语言的主流,在这种编程风格中,设计首先是将复杂的部分具体化,然后再将它们连续分成较小的部分;
- 使用自顶向下方法编写程序的技巧是编写一个主程序,程序编码完成后,程序就完成了;
- 自顶向下编程可能会使测试复杂化,因为直到项目接近尾声时才会有可执行的程序退出;
- C 和 Pascal 就是使用这种方法编程的一个例子;
- 在自下而上的设计中,系统的各个部分被详细规定。然后将这些部件连接起来,形成更大的组件,再将这些组件连接起来,直至形成一个完整的系统;
- 自下而上的设计所产生的程序更小、更灵活。一个较短的程序不必分成许多组件,而较少的组件意味着程序更容易阅读或修改;
- 自下而上的设计促进了代码的可重用性。当你编写两个或更多程序时,你为第一个程序编写的许多实用程序在后续程序中也会有用。因此,代码的可重用性是自底向上方法的主要优点之一;
- 自底向上的设计使程序更容易阅读;
- 自下而上的设计有助于理清程序设计的思路;
- 自下而上的程序设计可以让你进行单元测试,但在大部分系统组合起来之前,系统无法作为一个整体进行测试,这往往会导致在项目接近尾声时进行编译;
- C++ 和 java 就是使用这种方法编程的一个例子;
在计算机科学中,面向对象编程(OOP)是一种计算机编程范。面向对象编程的思想是,计算机程序可以被看作由一组个体单元或对象组成, 它们相互作用,而不是传统观点中将程序视为一组函数或简单地看作是向计算机发出的指令列表。每个对象能够接收消息、 处理数据,并向其他对象发送消息。每个对象都可以看作是一个独立的小机器或角色,具有明确的角色或责任。为了使一种语言成为 面向对象的编程语言,它必须支持三个面向对象的特征:
- 多态性(Polymorphism);
- 继承(Inheritence);
- 封装(Encapsulation); 它们一起被称为 PIE 原则。
在面向对象编程语言中,有以下基本概念:
- 类和对象(Class and Object);
- 封装(Encapsulation);
- 抽象(Abstraction);
- 数据隐藏(Data Hiding);
- 多态性(Polymorphism);
- 继承(Inheritence);
- 动态绑定(Dynamic Binding);
- 消息传递(Message Passing);
一个类被称为封装的基本单元。它是一个包含函数代码和数据的集合,构成了面向对象编程的基础。 类是一个抽象数据类型(Abstract Data Type, ADT),即类的定义仅提供逻辑抽象。在创建类型为类的变量时, 类内定义的数据和函数才开始其生命周期。类型为类的变量被称为对象,它具有物理存在,并且也被称为类的实例。 从一个类中可以创建多个对象。每个对象具有类中定义的相似数据集,并且可以使用类中定义的函数来操作数据。
例如:我们可以创建一个名为 car
的类,该类具有属性,如公司、型号、制造年份、燃料类型等,还可能具有动作,
如加速(acceleration()
)、刹车(brake()
)等。
对象是 C++ 程序中的基本运行时实体。所有对象都是类的实例。根据类的类型,一个对象可以代表任何东西, 比如一个人、手机、椅子、学生、雇员、书籍、讲师、演讲者、汽车、车辆或我们日常生活中看到的任何东西。 对象的状态由它们在特定实例中具有的数据值确定。对象占据内存空间,并且所有对象共享在创建类时定义的相同的数据项集。 两个对象可以通过函数传递消息来相互通信。
通俗地说:
- 动物可以被称为一个类,狮子、老虎、大象、狼、牛等可以看作是它的对象;
- 鸟可以被称为一个类,麻雀、老鹰、鹰、鸽子等可以看作是它的对象;
- 音乐家可以被称为一个类,Himesh Reshammiya、Anu Malik、Jatin-Lalit等可以看作是它的对象;
封装是将函数和数据绑定在一起的机制,形成一个称为类的紧凑形式。数据和函数可以是私有的或公共的。 私有数据/函数只能在类内部访问。公共数据/代码可以在类外部访问。封装的使用将实现的复杂性隐藏起来。 将函数代码和数据链接在一起产生了对象,这些对象是类类型的变量。
抽象是一种表示仅具有重要意义的基本特征并隐藏不重要细节的机制。要进行良好的抽象,我们需要对,使用面向对象编程原则实现的问题领域,有深刻的了解。作为抽象的例子,考虑一个名为 Vehicle
的类。当我们创建 Vehicle
类时,我们可以决定将什么样的函数代码和数据放入类中,例如车辆名称、轮胎数量、燃料类型、车辆类型等,以及函数如何改变档位、加速/减速车辆等。在这个时候,我们对车辆是如何工作的,比如加速、换挡的过程并不感兴趣。我们也不感兴趣使车辆的更多部分成为类的一部分,比如型号、车辆颜色等。
数据隐藏通过封装数据,阻止用户从外部访问数据。在面向对象编程语言中,我们有专用的关键字如 private
、protected
等,用于隐藏数据。
如果我们把Polymorphism一词分解,我们得到Poly意味着多,而Morphism意味着形式。
因此,多态性意味着多于一种形式。因此,多态性提供了一种让实体以多种形式行为的方式。通俗地说,多态性的一个很好的例子是 印度教方法中的克里希纳神。从程序员的角度来看,多态性意味着“一个接口多个方法”。
它是一种属性,允许一个接口控制对一般类别的操作的访问。例如,我们想要找出三个数字的最大值;无论我们传递什么类型的输入,
即整数、浮点数等。由于多态性,我们可以定义同名函数 max3
的三个不同版本。这个函数的每个版本都接受相同类型的三个参数,
即 max3
的一个版本接受三个整数类型的参数,另一个接受三个双精度浮点数类型的参数,依此类推。编译器根据传递给函数 max3
的数据的类型自动选择正确版本的函数。这也被称为函数多态性或函数重载。
多态性的类型:多态性有两种类型,如下所示:
- 编译时多态性;
- 运行时多态性;
继承是从早期存在的类派生出一个新类的机制。继承在面向对象编程中提供了可重用性的基本思想。新类继承了旧类的特性。 旧类和新类被称为(成对给出的)基类-派生类、父类-子类、超类-子类。
继承支持分类的概念。在分类中,我们可以形成不同类别的层次结构,每个类别除了具有一些共同属性之外,还具有一些特殊的特性。 通过分类,一个类只需要定义使其在其类别内成为独特的那些特性。
示例:
- 作为一个示例,在层次结构的最顶层,我们可以有一个
Vehicle
类。所有车辆的共同特征可以放在这个类中。从这个类中,我们可以派生一个新类,比如TwoWheeler
,其中包含仅特定于两轮车辆的特性; - 作为另一个示例,我们可以以工程学院作为顶级类,其子类为其各个部门,如计算机、电子、电气等。同样,工程学院可能有其父类作为其所隶属的大学;
Binding(绑定)意味着链接。它是将函数定义链接到函数调用的过程。
- 如果在编译时进行函数调用到函数定义的链接,即控制转移的位置,在这种情况下称为静态绑定;
- 当链接被延迟到运行时或在程序执行期间进行时,这种类型的链接称为动态绑定。响应于函数调用的函数将在程序执行时确定;
在 C++ 中,对象通过向彼此传递消息来进行通信。消息包含成员函数的名称和要传递的参数。在消息传递中,如下所示:
object.method(parameters);
这里的消息传递意味着对象调用方法并传递参数。消息传递实质上就是调用类的方法并传递参数,该方法会响应消息而执行。
- 程序被划分为类和函数;
- 数据被隐藏,无法被外部函数访问;
- 使用继承提供了代码的可重用性;
- 新的函数和数据项可以轻松添加;
- 数据比函数更为重要;
- 采用自下而上的方法;
- 数据和函数被捆绑在一个称为类的单元中;
- 对象通过以函数形式发送消息相互通信;
- 通过继承实现的代码可重用性;
- 面向对象系统可以轻松从一个平台升级到另一个平台;
- 复杂的项目可以轻松分解为小的代码函数;
- 抽象和封装的原则使程序员能够构建安全的程序;
- 软件复杂性减少;
- 数据隐藏的原则帮助程序员设计和开发安全的程序;
- 可以在短时间内快速开发软件;
- 同一类的多个实例可以在不受干扰的情况下共存;
一些最流行的面向对象编程语言包括:
- C++
- Java
- Smalltalk
- Eiffel
- Ruby
- Delphi
- Charm++
- Simula
只涉及类和对象而不具备继承、多态、封装等特性(不满足PIE原则)的语言被称为面向对象语言。在这些类型的语言中, 我们可以创建类和对象,并与它们一起工作。它们通常具有各种类型的内置对象。一些面向对象的语言包括 JavaScript、Visual Basic等。