成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面向“接口”編程和面向“實現”編程

開發 后端 前端
如果你已經讀了我的前幾篇關于面向對象范式因為受到Rust and Go等語言的影響而發生變化的文章,看到了我正在研究的Rust設計模式,你會發現我對Rust語言十分的偏愛。

[[81718]]

如果你已經讀了我的前幾篇關于面向對象范式因為受到Rust and Go等語言的影響而發生變化的文章,看到了我正在研究的Rust設計模式,你會發現我對Rust語言十分的偏愛。

除此之外,就在上周末,我讀完了經典的《設計模式:可復用面向對象軟件的基礎》。這些種種,引起了我對這本書中談及的一個核心原則的思考:

面向‘接口’編程,而不是面向‘實現’。

這是什么意思?

首先我們需要理解什么是‘接口’,什么是‘實現’。簡言之,一個接口就是我們要調用的一系列方法的集合,有對象將會響應這些方法調用。

一個實現就是為接口存放代碼和邏輯的地方。

本質上講,這個原則倡導的是,當我們寫一個函數或一個方法時,我們應該引用相應的接口,而不是具體的實現類。

面向‘實現’編程

首先我們看看,如果不遵循這個原則會發生什么。

假設你是《華氏451度》這本書里的“Montag”這個人。大家都知道,書在華氏451度會燒著的。小說中的消防隊員只要看到了書就會把它們丟到火里。我們用面向對象的視角說問題,書有一個叫做burn()的方法。

書并不是唯一會燃燒的東西。假設我們還有另外一個東西,比如木頭,它也有一個方法叫做burn()。我們用Rust語言來寫這段代碼,看看在不是面向‘接口’編程的情況下它們是如何燃燒的。

  1. struct Book {  
  2.     title: @str,  
  3.     author: @str,  
  4. }  
  5.  
  6. struct Log {  
  7.     wood_type: @str,  
  8. }  

很直接。我們創建了兩個結構體來表示一本書(Book)和一個木頭(Log)。下面我們為結構體實現它們的方法:

  1. impl Log {  
  2.     fn burn(&self) {  
  3.         println(fmt!("The %s log is burning!", self.wood_type));  
  4.     }  
  5. }  
  6.  
  7. impl Book {  
  8.     fn burn(&self) {  
  9.         println(fmt!("The book %s by %s is burning!", self.title, self.author));  
  10.     }  
  11. }  

現在LogBook 都有了 burn() 方法,讓我們把它們放到火上。

我們首先把木頭放到火上:

  1. fn start_fire(lg: Log) {  
  2.     lg.burn();  
  3. }  
  4.  
  5. fn main() {  
  6.     let lg = Log {  
  7.         wood_type: @"Oak",  
  8.         length: 1,  
  9.     };  
  10.  
  11.     // Burn the oak log!  
  12.     start_fire(lg);  
  13. }  

非常順利,我們得到了輸出 “The Oak log is burning!”.

現在,因為我們已經寫了一個 start_fire 函數,是否我們可以把書也傳進去,因為它們都有 burn()。讓我們試一下:

 

  1. fn main() {  
  2.     let book = Book {  
  3.         title: @"The Brothers Karamazov",  
  4.         author: @"Fyodor Dostoevsky",  
  5.     };  
  6.  
  7.     // Let's try to burn the book...  
  8.     start_fire(book);  
  9. }  

 

可行嗎?不行。出現了下面的錯誤:

mismatched types: expected Log but found Book (expected struct Log but
found struct Book)

#p#

說的非常清楚,因為我們寫出的函數需要的是一個Log結構體,而不是我們傳進去的 Book 結構體。如何解決這個問題?我們可以再寫一個這樣的方法,把參數改成Book結構體。然而,這并不是一個好的方案。我在兩個地方有了兩個幾乎一樣的函數,如果一個修改,我們需要記得修改另外一個。

現在讓我們看看面向‘接口’編程如何能解決這個問題。

面向接口編程

我們仍然使用前面的結構體,但這次我們加一個接口。在Rust語言里,接口叫做traits

  1. struct Book {  
  2.     title: @str,  
  3.     author: @str,  
  4. }  
  5.  
  6. struct Log {  
  7.     wood_type: @str,  
  8. }  
  9.  
  10. trait Burnable {  
  11.     fn burn(&self);  
  12. }  

現在,除了兩個結構體外,我們又多了一個叫做Burnable的接口。它的定義里只有一個叫做burn()的方法。我們來為每個結構體實現它們的接口:

  1. impl Burnable for Log {  
  2.     fn burn(&self) {  
  3.         println(fmt!("The %s log is burning!", self.wood_type));  
  4.     }  
  5. }  
  6.  
  7. impl Burnable for Book {  
  8.     fn burn(&self) {  
  9.         println(fmt!("The book \"%s\" by %s is burning!", self.title, self.author));  
  10.     }  

看起來并沒有多大的變化。這就是面向接口編程的強大之處:

  1. fn start_fire<T: Burnable>(item: T) {  
  2.     item.burn();  
  3. }  

不僅僅只能接收一個Book對象或Log對象做參數,我們可以往里面傳入任何實現了 Burnable 接口的類型(我們叫它類型T)。這使得我們的主函數可以寫成這樣:

  1. fn main() {  
  2.     let lg = Log {  
  3.         wood_type: @"Oak",  
  4.     };  
  5.  
  6.     let book = Book {  
  7.         title: @"The Brothers Karamazov",  
  8.         author: @"Fyodor Dostoevsky",  
  9.     };  
  10.  
  11.     // Burn the oak log!  
  12.     start_fire(lg);  
  13.  
  14.     // Burn the book!  
  15.     start_fire(book);  
  16. }  

正如期望的,我們得到了下面的輸出:

The Oak log is burning!

The book “The Brothers Karamazov” by Fyodor Dostoevsky is burning!

這跟我們期望的完全一致。

結論

遵循“面向‘接口’編程”原則,我們可以寫出一個函數,使其能完全能復用任何實現了Burnable接口的對象。因為很多的程序員都是按小時收費的,我們寫出越多可復用的代碼,用于維護它們的時間就會越少,也就是更好。

因此,這是一個非常強大的編程思想。

并不是什么時候都可以面向接口編程的,但遵循這種原則會讓你更容易的寫出可復用的更優雅的代碼。接口提供了非常優秀的抽象歸納,讓我們的開發工作變得容易很多。

英文原文:Program to an Interface, Fool

譯文鏈接:http://www.aqee.net/program-to-an-interface-fool/

責任編輯:林師授 來源: 外刊IT評論
相關推薦

2009-07-02 13:25:00

消除實現繼承面向接口編程Java

2022-07-30 23:41:53

面向過程面向對象面向協議編程

2020-07-23 17:29:47

接口編程代碼

2021-01-14 08:16:41

Python接口編程

2023-02-22 18:06:35

函數javascript面向對象編程

2009-06-22 11:27:59

反向控制原理面向切面編程Spring

2010-11-17 11:31:22

Scala基礎面向對象Scala

2012-02-10 10:32:33

JavaSpring

2012-01-17 09:34:52

JavaScript

2017-04-21 09:07:39

JavaScript對象編程

2023-10-04 17:25:01

面向接口編程

2023-11-07 16:00:25

面向切面編程開發

2015-03-20 09:54:44

網絡編程面向連接無連接

2016-12-12 15:22:41

編程

2012-12-13 11:01:42

IBMdW

2009-08-24 09:46:40

面向切面編程AOP

2014-05-08 14:13:00

Java面向GC

2012-02-27 09:30:22

JavaScript

2023-11-30 08:00:54

面向對象面向切面

2023-10-13 07:36:58

Java函數式編程
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 午夜精品久久久久久久久久久久久 | 韩日精品视频 | 不卡一区二区在线观看 | 亚洲精品无人区 | 午夜tv免费观看 | 精品视频999| 欧美国产激情二区三区 | 午夜爱爱毛片xxxx视频免费看 | 成人精品视频 | 免费在线观看av的网站 | a在线视频 | 成年网站在线观看 | 天天精品在线 | 黄毛片| 国产高清精品在线 | 久久91精品| 九九免费在线视频 | 国产日韩欧美精品 | 综合五月婷 | 天天干干 | 天天插天天干 | www.久久久久久久久久久 | 日韩一区中文字幕 | 日韩精品视频一区二区三区 | 亚洲一区二区精品视频在线观看 | 亚洲一区二区免费 | 99精品欧美一区二区三区 | 久久一区视频 | 91看片在线观看 | 亚洲高清一区二区三区 | 亚洲精品久久久久中文字幕欢迎你 | 日本一二区视频 | 成人天堂 | 国产成人a亚洲精品 | 免费视频一区二区 | 欧美日韩成人影院 | 久久国产高清视频 | 亚洲一区日韩 | 午夜欧美a级理论片915影院 | 欧美一区二区三区久久精品视 | 国产亚洲精品精品国产亚洲综合 |