Main Content

为什么使用面向对象的设计

MATLAB 程序的编程方式

创建软件应用程序通常包括设计应用程序数据和实施对这些数据执行的操作。过程式程序将数据传递给函数,函数对数据执行必要的操作。面向对象的软件将数据和操作封装在各个对象中,这些对象通过各自的接口进行交互。

您可以通过 MATLAB® 语言使用过程式编程方式和面向对象的编程方式来创建程序,并在程序中结合使用对象和普通函数。

过程式程序设计

在过程式编程中,您需要设计一系列步骤,通过执行这些步骤来实现所需状态。通常,您会将数据表示为结构体的单个变量或字段。您可以将操作实现为以变量为参量的函数。程序通常调用一系列函数,每个函数都接受传递的数据,然后返回修改后的数据。每个函数都会对数据执行一项或多项操作。

面向对象的程序设计

面向对象的程序设计包括:

  • 确定要构建的系统或应用程序的组件

  • 分析和识别模式,以确定哪些组件会重用或共享特征

  • 基于相似性和差异性对组件进行分类

执行此分析后,您可以定义类来说明应用程序所使用的对象。

类和对象

类描述一组具有共同特征的对象。对象是类的特定实例。对象属性中包含的值使对象不同于同一类的其他对象。由类定义的函数(称为方法)实现类中所有对象通用的对象行为。

何时创建面向对象的程序

简单的编程任务可以用简单的函数来实现。然而,随着任务的规模和复杂度的增加,函数会变得更加复杂和难以管理。

当函数变得太大时,您可以将它们分成较小的函数,并将数据从一个函数传递到另一个函数。然而,随着函数数量的增加,设计和管理传递给函数的数据也变得困难和容易出错。在这种情况下,可以考虑将您的 MATLAB 编程任务转向面向对象的设计。

从对象的角度来理解问题

对某些问题来说,从对象的角度来考虑会更简单、更自然。将问题陈述中的名词视为要定义的对象,动词视为要执行的操作。

例如,我们可以设计类来表示货币借贷机构,如银行、抵押贷款公司、个人货币贷方等。上述各种类型的贷方很难用过程表示。但是,您可以将每类贷方表示为执行特定操作并包含特定数据的对象。设计对象的过程包括识别对您的应用程序很重要的贷方特征。

确定共同点.  所有贷方有哪些共同点?例如,所有 MoneyLender 对象都可能具有 loan 方法和 InterestRate 属性。

确定差异.  每个贷方有什么不同?一个贷方可以向企业提供贷款,而另一个贷方只向个人提供贷款。因此,对于不同类型的贷款机构,loan 操作可能需要有所不同。MoneyLender 基类的子类可特化 loan 方法的子类版本。每个贷方可以为其 InterestRate 属性设置不同值。

将共性析出为一个超类,并实现子类中每种类型的贷方的特性。

只添加必要的内容.  这些机构从事的某些活动可能与您的应用程序无关。在设计阶段,请根据您的问题定义来确定对象必须包含的操作和数据。

对象管理内部状态

对象可提供结构体和元胞数组中无法提供的一些有用功能。例如,对象可以:

  • 约束赋给任何给定属性的数据值

  • 仅在查询属性时计算属性值

  • 查询或更改任何属性值时广播通知

  • 限制对属性和方法的访问

减少冗余

随着程序复杂度的增加,面向对象的设计的好处变得更加明显。例如,假设您将以下过程作为应用程序的一部分来实现:

  1. 检查输入

  2. 对第一个输入参量执行计算

  3. 基于第二个输入参量转换步骤 2 的结果

  4. 检查输出和返回值的有效性

您可以将此过程作为普通函数来实现。但是,假设您要在应用程序中的某个地方再次使用此过程,则除步骤 2 之外,您必须执行不同的计算。您可以复制并粘贴第一个实现,然后重写步骤 2。您也可以创建一个根据选项执行相应计算的函数,然后依此类推。然而,这些选项会导致代码更复杂。

面向对象的设计可以将公共代码析出为一个基类。该基类将定义所使用的算法,并实现在所有使用该代码的情况下都通用的内容。步骤 2 可以通过语法进行定义,但不进行实现,而将特化实现留给从这个基类派生的类。

步骤 1:

function checkInputs()
   % actual implementation
end

步骤 2:

function results = computeOnFirstArg()
   % specify syntax only
end

步骤 3:

function transformResults()
   % actual implementation
end

步骤 4:

function out = checkOutputs()
   % actual implementation
end

不必复制或修改基类中的代码。从基类派生的类会继承这些代码。继承能减少要测试的代码量,并将程序与对基本过程的更改隔离开来。

定义一致的接口

在面向对象的编程中,一种有用的编程方式是基于某个类来创建类似但更特化的类。此类定义公用接口。在您的程序设计中使用这种类可以:

  • 确定特定目标的需求

  • 将需求作为接口类编写到您的程序中

降低复杂度

对象减少了您使用组件或系统时必须具备的知识,从而降低了复杂度:

  • 对象提供隐藏实现细节的接口。

  • 对象实施控制对象交互方式的规则。

为了说明这些优点,我们以一个称为双链表的数据结构体的实现为例。有关实际的实现,请参阅通过类实现链表

以下是一个三元素列表的图:

Three elements of a doubly linked list

要向列表中添加一个节点,请断开列表中的现有节点,插入新节点,然后适当地重新连接节点。以下是基本步骤:

首先断开节点连接:

  1. 取消 n2.Prevn1 的链接

  2. 取消 n1.Nextn2 的链接

现在创建新节点,连接它,并对原始节点重新编号:

  1. new.Prev 链接到 n1

  2. new.Next 链接到 n3(原来是 n2

  3. n1.Next 链接到 new(将是 n2

  4. n3.Prev 链接到 new(将是 n2

Doubly linked list

方法如何执行这些步骤的详细信息封装在类设计中。每个节点对象都包含将自身插入列表中或从列表中删除自身的功能。

例如,在此类中,每个节点对象都有一个 insertAfter 方法。要向列表中添加节点,请创建节点对象,然后调用其 insertAfter 方法:

nnew = NodeConstructor;
nnew.insertAfter(n1)

由于节点类定义实现这些操作的代码,因此这段代码:

  • 由类编写者以最佳方式实现

  • 始终与最新版本的类保持一致

  • 经过适当测试

  • 会在从 MAT 文件加载对象时自动更新旧版对象。

对象方法会强制实施节点交互规则。采用这种设计,便无需在使用这些对象的应用程序中设计强制实施规则。这也意味着应用程序在其自身的过程实现中产生错误的可能性降低。

便于模块化

当您将系统分解成对象(汽车 –> 引擎 –> 燃油系统 –> 氧气传感器)时,您就根据自然边界划分了模块。类对代码模块化提供三个级别的控制:

  • 公共 - 任何代码都可以访问此特定属性或调用此方法。

  • 受保护 - 只有此对象的方法和从此对象的类派生的对象的方法才能访问此属性或调用此方法。

  • 私有 - 只有对象自己的方法才能访问此属性或调用此方法。

重载的函数和运算符

定义类时,可以重载现有 MATLAB 函数来处理新对象。例如,MATLAB 串行端口类可重载 fread 函数,从连接到此对象所代表的端口的设备读取数据。如果您定义了用于表示数据的类,您可以为其定义各种运算,例如相等 (eq) 或加法 (plus)。

相关主题