首页 课程 师资 教程 报名

面向对象语言的特点

  • 2022-10-25 09:56:04
  • 548次 星辉

编程社区对于必须将语言的哪些特性视为面向对象没有达成共识。Rust 受到许多编程范式的影响,包括 OOP;例如,函数式编程的特性。可以说,OOP 语言具有某些共同特征,即对象、封装和继承。让我们看看这些特性中的每一个意味着什么,以及 Rust 是否支持它。

隐藏实现细节的封装

通常与 OOP 相关的另一个方面是封装的思想,这意味着使用该对象的代码无法访问对象的实现细节。因此,与对象交互的唯一方法是通过其公共 API;使用对象的代码不应该能够进入对象的内部并直接更改数据或行为。这使程序员能够更改和重构对象的内部结构,而无需更改使用该对象的代码。

如何控制Java封装:我们可以使用pub关键字来决定我们代码中的哪些模块、类型、函数和方法应该是公共的,默认情况下其他的都是私有的。例如,我们可以定义一个结构体,该结构体AveragedCollection具有一个包含i32值向量的字段。该结构还可以有一个字段,其中包含向量中值的平均值,这意味着不必在任何人需要时按需计算平均值。换句话说,AveragedCollection将为我们缓存计算出的平均值。示例具有 AveragedCollection结构的定义:

文件名:src/lib.rs

pub struct AveragedCollection {
    list: Vec<i32>,
    average: f64,
}

结构被标记pub以便其他代码可以使用它,但结构中的字段保持私有。这在这种情况下很重要,因为我们希望确保无论何时从列表中添加或删除一个值,平均值也会更新。我们通过在结构上实现 、 和 方法来做到这一点add,remove如average示例所示:

文件名:src/lib.rs

impl AveragedCollection {
    pub fn add(&mut self, value: i32) {
        self.list.push(value);
        self.update_average();
    }
    pub fn remove(&mut self) -> Option<i32> {
        let result = self.list.pop();
        match result {
            Some(value) => {
                self.update_average();
                Some(value)
            }
            None => None,
        }
    }
    pub fn average(&self) -> f64 {
        self.average
    }
    fn update_average(&mut self) {
        let total: i32 = self.list.iter().sum();
        self.average = total as f64 / self.list.len() as f64;
    }
}

公共方法add,remove和average是访问或修改 的实例中的数据的唯一方法AveragedCollection。当使用该方法添加项目list或add使用该方法删除项目时,每个项目的实现都会调用处理更新字段remove的私有方法。update_averageaverage

我们将listandaverage字段保留为私有,因此外部代码无法直接在字段中添加或删除项目list;否则,该字段可能会在 更改average时变得不同步。list该average方法返回average字段中的值,允许外部代码读取average但不能修改它。

因为我们已经封装了 struct 的实现细节,所以 AveragedCollection我们将来可以很容易地更改数据结构等方面。例如,我们可以在字段中使用 aHashSet<i32>而不是 a 。只要 、 和 public 方法的签名保持不变,使用的代码 就不需要更改。如果我们改为公开,则不一定是这种情况:并且添加和删除项目的方法不同,因此如果直接修改外部代码,则可能必须更改。

Vec<i32>listaddremoveaverageAveragedCollectionlistHashSet<i32>Vec<i32>list

如果封装是一种语言被视为面向对象的必要方面,那么 Rust 就满足了这一要求。对代码的不同部分使用或不使用的选项pub可以封装实现细节。

继承作为类型系统和代码共享

继承是一种机制,一个对象可以从另一个对象的定义中继承元素,从而获得父对象的数据和行为,而无需再次定义它们。

如果一种语言必须具有继承性才能成为一种面向对象的语言,那么 Rust 不是一种。如果不使用宏,就无法定义继承父结构的字段和方法实现的结构。

但是,如果您习惯于在编程工具箱中使用继承,则可以在 Rust 中使用其他解决方案,具体取决于您首先实现继承的原因。

你会选择继承有两个主要原因。一种是代码的重用:您可以为一种类型实现特定的行为,而继承使您能够为不同的类型重用该实现。summarize您可以使用默认 trait 方法实现在 Rust 代码中以有限的方式执行此操作,当我们在trait 上添加方法的默认实现时,您可以在清单 10-14 中看到Summary。任何实现该Summary特征的类型都将拥有summarize可用的方法,而无需任何进一步的代码。这类似于具有方法实现的父类和也具有方法实现的继承子类。我们也可以在实现的summarize时候覆盖方法的默认实现Summarytrait,类似于子类覆盖从父类继承的方法的实现。

使用继承的另一个原因与类型系统有关:使子类型能够在与父类型相同的地方使用。这也称为多态性,这意味着如果多个对象共享某些特征,您可以在运行时相互替换多个对象。

对象包含数据和行为

Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides所著的《Design Patterns: Elements of Reusable Object-Oriented Software》(Addison-Wesley Professional,1994 年),俗称“四人帮”一书,是一个对象目录——面向设计模式。它以这种方式定义 OOP:

面向对象的程序是由对象组成的。一个对象将数据和对该数据进行操作的过程打包在一起。这些过程通常称为方法或操作。

使用这个定义,Rust 是面向对象的:结构和枚举有数据,impl块提供结构和Java枚举的方法。根据四人帮对对象的定义,尽管带有方法的结构和枚举不称为对象,但它们提供了相同的功能。

选你想看

你适合学Java吗?4大专业测评方法

代码逻辑 吸收能力 技术学习能力 综合素质

先测评确定适合在学习

在线申请免费测试名额
价值1998元实验班免费学
姓名
手机
提交