专注Java教育14年 全国咨询/投诉热线:400-8080-105
动力节点LOGO图
始于2009,口口相传的Java黄埔军校
首页 hot资讯 面向对象的特征

面向对象的特征

更新时间:2021-08-25 11:06:51 来源:动力节点 浏览594次

面向对象语言的特点

在编程社区中,对于一种语言必须被视为面向对象的哪些特性,没有达成共识。Rust 受到许多编程范式的影响,包括 OOP;例如,我们在第 13 章探讨了函数式编程的特性。可以说,OOP 语言具有某些共同的特性,即对象、封装和继承。让我们看看每个特性的含义以及 Rust 是否支持它。

对象包含数据和行为

Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合着的Design Patterns: Elements of Reusable Object-Oriented Software一书(Addison-Wesley Professional,1994 年)通俗地称为The Gang of Four一书,是面向对象的目录设计模式。它以这种方式定义 OOP:

面向对象的程序由对象组成。一个对象既打包了数据,也打包了对这些数据进行操作的过程。这些过程通常称为方法或操作。

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

隐藏实现细节的封装

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

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

文件名:src/lib.rs

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

示例 17-1:一个AveragedCollection维护整数列表和集合中项目平均值的结构体

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

文件名: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;
    }
}

清单17-2:公共方法的实现 add,remove以及average对AveragedCollection

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

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

因为我们已经封装了 struct 的实现细节,所以 AveragedCollection我们可以在未来轻松更改方面,例如数据结构。例如,我们可以使用 aHashSet而不是 a Vec作为list字段。只要的签名add, remove和average公众使用的方法保持不变,代码 AveragedCollection就不需要改变。如果我们list改为公开,则情况不一定如此:HashSet并且Vec有不同的添加和删除项目的方法,因此如果list直接修改外部代码,则可能必须更改。

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

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

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

如果一种语言必须具有继承性才能成为面向对象的语言,那么 Rust 不是一个。无法定义继承父结构的字段和方法实现的结构。但是,如果您习惯于在您的编程工具箱中使用继承,您可以在 Rust 中使用其他解决方案,这取决于您首先使用继承的原因。

您选择继承有两个主要原因。一种是代码重用:您可以为一种类型实现特定的行为,而继承使您能够为不同的类型重用该实现。你可以使用默认的 trait 方法实现来共享 Rust 代码,当我们summarize在Summarytrait上 添加方法的默认实现时,你在示例 10-14 中看到了这一点。任何实现Summarytrait 的类型都可以使用该 summarize方法,而无需任何进一步的代码。这类似于具有方法实现的父类和也具有方法实现的继承子类。我们还可以在实现summarize方法时覆盖该方法 的默认实现Summary trait,类似于覆盖从父类继承的方法的实现的子类。

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

多态性

对很多人来说,多态是继承的同义词。但它实际上是一个更一般的概念,指的是可以处理多种类型数据的代码。对于继承,这些类型通常是子类。

相反,Rust 使用泛型来抽象不同的可能类型和特征边界,以对这些类型必须提供的内容施加约束。这有时称为有界参数多态性。

继承最近在许多编程语言中作为一种编程设计解决方案失宠,因为它经常面临共享不必要的代码的风险。子类不应该总是共享其父类的所有特征,而是通过继承来实现。这会降低程序设计的灵活性。它还引入了在子类上调用方法的可能性,这些方法没有意义或由于方法不适用于子类而导致错误。此外,有些语言只允许一个子类继承一个类,进一步限制了程序设计的灵活性。

由于这些原因,Rust 采取了不同的方法,使用 trait 对象而不是继承。让我们看看 trait 对象是如何在 Rust 中实现多态的。

以上就是动力节点小编介绍的"面向对象的特征",希望对大家有帮助,想了解更多可查看Java教程。动力节点在线学习教程,针对没有任何Java基础的读者学习,让你从入门到精通,主要介绍了一些Java基础的核心知识,让同学们更好更方便的学习和了解Java编程,感兴趣的同学可以关注一下。

提交申请后,顾问老师会电话与您沟通安排学习

免费课程推荐 >>
技术文档推荐 >>