
华为云正在采取行动加快企业数字化转型>>>


如果您阅读了我以前的有关因Rust和Go等语言的影响而导致的面向对象范式更改的文章,并且看到了我正在研究的Rust设计模式,您会发现我非常感兴趣在Rust语言首选项中.
此外,就在上周末,我读完了经典的“设计模式: 可重用的面向对象软件的基础知识”. 所有这些使我开始思考本书中讨论的核心原则之一:
为“界面”而非“实现”编程.
首先,我们需要了解什么是“界面”和什么是“实现”. 简而言之,接口是我们要调用的方法的集合,某些对象将响应这些方法调用.
一种实现是在其中存储接口的代码和逻辑.

从本质上讲,该原则主张在编写函数或方法时,应引用相应的接口,而不是特定的实现类.
首先,让我们看看如果不遵循该原则会发生什么情况.
假设您是《华氏451度》一书中的“蒙塔格”人. 每个人都知道书本会在华氏451度燃烧. 小说中的消防员一看到书就会将书扔到火上. 我们从面向对象的角度讨论这个问题. 这本书有一种叫做burn()的方法.
书不是唯一燃烧的东西. 假设我们还有另一件事,例如木头,它也有一个称为burn()的方法. 让我们用Rust语言编写此代码,看看当不为“接口”编程时它们如何燃烧.
struct Book {
title: @str,
author: @str,
}
struct Log {
wood_type: @str,
}
很简单. 我们创建了两个结构来表示一本书(Book)和一个日志(Log). 在这里,我们实现其结构方法:
impl Log {
fn burn(&self) {
println(fmt!("The %s log is burning!", self.wood_type));
}
}
impl Book {
fn burn(&self) {
println(fmt!("The book %s by %s is burning!", self.title, self.author));
}
}
现在Log和Book都具有burn()方法,让我们着火.

我们首先把木头放火上
fn start_fire(lg: Log) {
lg.burn();
}
fn main() {
let lg = Log {
wood_type: @"Oak",
length: 1,
};
// Burn the oak log!
start_fire(lg);
}
非常顺利,我们得到了输出“橡木日志正在燃烧!”.
现在,因为我们已经编写了start_fire函数,我们是否也可以传递这些书,因为它们都具有burn(). 试试吧:
fn main() {
let book = Book {
title: @"The Brothers Karamazov",
author: @"Fyodor Dostoevsky",
};
// Let's try to burn the book...
start_fire(book);
}
可行吗?没门. 发生以下错误:
不匹配的类型: 预期的Log,但找到Book(预期的结构Log,但
找到结构书)

非常清楚,因为我们编写的函数需要一个Log结构,而不是我们传入的Book结构. 如何解决此问题?我们可以编写另一种方法来将参数更改为Book结构. 但是,这不是一个好的解决方案. 我在两个地方有两个几乎相同的功能. 如果修改了一个面向接口编程,我们需要记住要修改另一个.
现在让我们看看“界面”编程如何解决这个问题.
我们仍然使用以前的结构,但是这次我们添加一个接口. 在Rust语言中,该界面称为特征:
struct Book {
title: @str,
author: @str,
}
struct Log {
wood_type: @str,
}
trait Burnable {
fn burn(&self);
}
现在,除了这两种结构外,我们还有一个名为Burnable的接口. 在其定义中只有一种方法称为burn(). 让我们为每种结构实现其接口:
impl Burnable for Log {
fn burn(&self) {
println(fmt!("The %s log is burning!", self.wood_type));
}
}
impl Burnable for Book {
fn burn(&self) {
println(fmt!("The book \"%s\" by %s is burning!", self.title, self.author));
}
}
看起来没什么不同. 这就是面向接口编程的力量:
fn start_fire<T: Burnable>(item: T) {
item.burn();
}

不仅可以接收Book对象或Log对象作为参数,我们还可以传入实现Burnable接口的任何类型(我们将其称为T类型). 这使我们的主要功能可以这样编写:
fn main() {
let lg = Log {
wood_type: @"Oak",
};
let book = Book {
title: @"The Brothers Karamazov",
author: @"Fyodor Dostoevsky",
};
// Burn the oak log!
start_fire(lg);
// Burn the book!
start_fire(book);
}
如预期的那样,我们得到以下输出:
橡木原木正在燃烧!
费奥多尔·陀思妥耶夫斯基(Fyodor Dostoevsky)写的《卡拉马佐夫兄弟》一书正在燃烧!
这正是我们所期望的.
按照“面向接口编程”的原理,我们可以编写一个函数,以便它可以完全重用实现Burnable接口的任何对象. 因为许多程序员是按小时收费的,所以我们编写的代码越重用,维护它们所需的时间就越少,这更好.
因此,这是一个非常强大的编程思想.
并非总是可以进行面向接口的编程,但是遵循此原理将使您更容易编写可重用且更优雅的代码. 该界面提供了很好的抽象归纳,使我们的开发工作更加轻松.
[英语原文: 编程接口面向接口编程,傻瓜]
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-197812-1.html
人家导弹都装在发射筒里真是阿Q精神