簡述
在過往的工作中,我發(fā)現(xiàn)很多人搞不清面向?qū)ο蠛兔嫦蜻^程的區(qū)別,總認為使用面向?qū)ο缶幊陶Z言來開發(fā),就是在面向面向?qū)ο缶幊塘?。而實際上,他們只是在用面向?qū)ο缶幊陶Z言,編寫面向過程風格的代碼而已,并沒有發(fā)揮面向?qū)ο缶幊痰膬?yōu)勢。這就相當于手握一把屠龍刀,卻只把它當做一把普通的到來使用。
1.什么是面向過程編程與面向過程編程語言?
如果你是一名比較資深的程序員,最開始學習編程的時候接觸的是 Basic、C等面向過程的編程語言,那么你對這兩個概念肯定不陌生。但是如果你是新生代的程序員,一開始學習編程的時候,接觸的就是面向?qū)ο缶幊陶Z言,那你對這兩個概念可能不熟悉。所以,在對比面向?qū)ο笈c面向過程優(yōu)劣之前,我們先把面向過程編程和面向過程編程語言這兩個概念搞清楚。
我們可以比對這面向?qū)ο缶幊毯兔嫦驅(qū)ο缶幊陶Z言這兩個概念來理解面向過程編程和面向過程編程語言。我們來回顧下面向?qū)ο缶幊毯兔嫦驅(qū)ο缶幊陶Z言:
- 面向?qū)ο缶幊淌且环N編程范式或編程風格。它以類或?qū)ο笞鳛榻M織代碼的基本單元,并將封裝、抽象、繼承、多態(tài)這四個特性,作為代碼設計和實現(xiàn)的基石。
- 面向?qū)ο缶幊陶Z言支持類或?qū)ο蟮恼Z法機制,能方便地實現(xiàn)面向?qū)ο缶幊趟拇筇匦缘木幊陶Z言。
類比面向?qū)ο缶幊毯兔嫦驅(qū)ο缶幊陶Z言的定義,對于面向過程編程和面向過程編程語言這個兩個概念,我給出下面這樣的定義。
- 面向過程編程也是一種編程范式或編程風格。它以過程(可理解為方法、函數(shù)、操作)作為組織代碼的基本單元,以數(shù)據(jù)(可理解為變量)與方法相分離為主要的特點。面向過程風格是一種流程化的編程風格,通過拼接一組順序執(zhí)行的方法來操作數(shù)據(jù)完成一項功能。
- 面向過程編程語言首先是一種編程語言。它最大的特點是不支持類和對象這兩個語法概念,不支持風格的面向?qū)ο缶幊烫匦?,僅支持面向過程編程。
用一個例子來解釋下。假設有一個記錄了用戶信息的文件 users.txt,每行文本的格式是 name&age&gender(如小王&28&男
)。編寫一個程序來逐行讀取用戶信息,然后格式化成 name,age,gender
這種格式,并且按照 age 從小達到排序后,重新寫入另一個文件 formatted_user.txt。
首先,使用面向過程編程風格來編寫這個程序,使用 C 語言來編寫。
struct User {
char name[64];
int age;
char gender[16];
}
struct User parse_to_user(char* text) {
// 將text“小王&28&男” 解析成結構體 struct User
}
char* format_to_text(struct User user) {
// 將結構體User格式化成文本 “小王,28,男”
}
void sort_users_by_age(struct User users[]) {
// 按照年齡從小到大排序users
}
void format_user_file(char* file_path, char* new_file_path) {
// 打開文件...
struct User users[1024]; // 假設最大1024個用戶
int count = 0;
while(1) {// 讀取文件,直到讀取結束
// 從文件內(nèi)讀取一行內(nèi)容...
struct User user = parse_to_user(line);
users[count++] = user;
}
sort_users_by_age(users);
int i;
for(i = 0; i < count; i++) {
char* formatted_to_text = format_to_text(users[i]);
// 寫入formatted_to_text到文件...
}
// 關閉文件...
}
int main(char ** args, int argv) {
format_user_file("/file/user.txt", "/file/formatted_user.txt");
}
在看看面向?qū)ο筮@種風格編寫出來的代碼是什么樣子的。
public class User {
private String name;
private int age;
private String gender;
public User(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public static User parseFrom(String userInfoText) {
// 將 “小王&28&男” 解析成類User
}
public String formatToText() {
// 將類User轉(zhuǎn)化成文本 “小王,28,男”
}
}
public class UserFileFormatter {
public void format(String userFile, String formattedUserFile) {
// 打開文件...
List<User> users = new ArrayList<>();
while (true) { // 讀取文件,直到讀取結束
// 從文件內(nèi)讀取一行數(shù)據(jù)...
User user = User.parseFrom(userInfoText);
users.add(user);
}
// 按照年齡排序...
for (int i = 0; i < users.size(); i++) {
String formattedUserText = users.get(i).formatToText();
// 寫入到新文件...
}
// 關閉文件...
}
}
public class MainApplication {
public static void main(String[] args) {
UserFileFormatter userFileFormatter = new UserFileFormatter();
userFileFormatter.format("/file/user.txt", "/file/formatted_user.txt");
}
}
從上面代碼,可以看出,面向過程和面向?qū)ο笞罱膮^(qū)別是,代碼的組織方式不同。面向過程風格的代碼組織成立一組方法集合及其數(shù)據(jù)結構(struct User),方法和數(shù)據(jù)定義是分開的。而面向?qū)ο箫L格的代碼被組織成一組類,方法和數(shù)據(jù)結構被綁定一起,定義在類中。
可能有人會覺得,上面這兩個例子的面向?qū)ο缶幊毯兔嫦蜻^程編程,這兩個風格的區(qū)別貌似不是很大呀。
2.面向?qū)ο缶幊瘫让嫦蜻^程編程有哪些優(yōu)勢?
為什么面向?qū)ο缶幊掏碛诿嫦蜻^程編程出現(xiàn),卻能取而代之,稱為主流的編程范式?面向?qū)ο缶幊毯兔嫦蜻^程編程比起來,到底有哪些優(yōu)勢?
2.1 OOP 更加能夠應對大規(guī)模復雜程序的開發(fā)
剛剛的例子,你可能感覺兩種風格的代碼貌似差不多,頂多就是代碼組織方式有點區(qū)別,沒有感覺到面向?qū)ο缶幊逃惺裁磧?yōu)勢。其實,主要原因就是因為這個例子比較簡單、不夠復雜。
對于簡單的開發(fā)來說,不管是用面向過程編程風格,還是面向?qū)ο缶幊田L格,差別確實不會很大,甚至有時候面向過程的編程風格反而更有優(yōu)勢。因為整個程序的處理流程只有一條主線,很容易被劃分成順序執(zhí)行的幾個步驟,然后逐句翻譯成代碼,這就非常適合采用面向過程這種面條式的編程風格來實現(xiàn)。
但是,對于大模型復雜程序的開發(fā)來說,整個程序的處理流程錯綜復雜,并非只有一條主線。如果把整個程序的處理流程畫出來的話,會是一個網(wǎng)狀結構。如果再用面向過程編程來實現(xiàn),就會比較吃力了。這個時候,面向?qū)ο蟮木幊田L格的優(yōu)勢就比較明顯了。
面向?qū)ο缶幊淌且灶悶樗伎紝ο?。在進行面向?qū)ο缶幊痰臅r候,并不是一上來就去思考將流程拆為一個個方法,而是先去思考如何給業(yè)務建模,將需求翻譯為類,如何給類之間建立交互關系,而完成這些工作完全不需要考慮錯綜復雜的處理流程。當有了類的設計之后,再像搭積木一樣,按照處理流程將類組裝起來形成整個程序。這種開發(fā)模式、思考問題的方式,能讓我們在應對復雜程序開發(fā)的時候,思路更加清晰。
此外,面向?qū)ο缶幊踢€提供了一種更加清晰的、更加模塊化的代碼組織方式。比如,我們開發(fā)一個電商系統(tǒng),業(yè)務邏輯發(fā)咋、代碼量很大,可能要定義數(shù)百個函數(shù)、數(shù)百個數(shù)據(jù)結構,如何分門別類地組織這些函數(shù)和數(shù)據(jù)結構,才能看起來不至于凌亂呢?類就是一種非常好的組織這些函數(shù)和數(shù)據(jù)結構的方式,是一種將代碼模塊化的有效手段。
有人可能互說,像 C 語言這種面向過程的編程語言,也可以按照功能的不同,把函數(shù)和數(shù)據(jù)結構放到不同的文件里,以達到給函數(shù)和數(shù)據(jù)結構分類的目的。不過,面向?qū)ο缶幊瘫旧硖峁┝祟惖母拍?,強制你做這件事情,而面向過程編程并不強求。這也算是面向?qū)ο缶幊陶Z言的一個小小的創(chuàng)新吧。
實際上,利用面向過程的編程語言照樣可以寫出面向?qū)ο箫L格的代碼,只不過可能會比使用面向?qū)ο缶幊陶Z言來說,付出的代碼要高一些。而且,面向過程編程和面向?qū)ο缶幊滩⒎峭耆珜αⅰ?/p>
2.2 OOP 風格的代碼更易復用、易擴展、易維護
剛剛的例子比較簡單,只用到了類、對象這兩個基本的概念,并沒有用到更加高級的四大特性。因此,面向?qū)ο缶幊痰膬?yōu)勢其實并沒有發(fā)揮出來。
面向?qū)ο缶幊烫峁┑姆庋b、抽象、繼承、多態(tài)這些特性,能極大地滿足復雜的編程需求,能方便我們寫出更易復用、易擴展、易維護的代碼。
- 首先,封裝特性將數(shù)據(jù)和方法綁定在一起,通過訪問權限控制,只允許外部調(diào)用者通過類暴露的有限方法訪問數(shù)據(jù),而不會像面向過程那樣,數(shù)據(jù)可以被任意訪問和修改。因此,面向?qū)ο缶幊烫峁┑姆庋b特性更有利于提高代碼的易維護性。
- 其次,再看下抽象特性。我們知道,函數(shù)本身就是一種抽象,它隱藏了具體的實現(xiàn)。在使用函數(shù)的時候,只需要了解函數(shù)具體有什么功能,而不需要了解它是怎么實現(xiàn)的。從這一點上,不管面向?qū)ο缶幊?,還是面向過程編程,都支持抽象特性。不管,面對對象編程還提供了其他抽象特性的實現(xiàn)方式,這些實現(xiàn)方式是面向過程所不具備的,比如基于接口實現(xiàn)的抽象?;诮涌诘某橄?,可以讓我們在不改變原有實現(xiàn)的情況下,輕松替換新的實現(xiàn)邏輯,提高帶代碼的可擴展性。
- 接著,繼承特性是面向?qū)ο缶幊滔啾扔诿嫦蜻^程編程所特有的兩個特性之一(另一個是多態(tài))。如果兩個類有一些相同的屬性和方法,我們就可以將這些相同的代碼,抽取到父類中,讓兩個子類繼承父類。這樣兩個子類也可以重用父類中的代碼,避免了代付重復多謝,提高了代碼的復用性。
- 最后,在看下多態(tài)這個特性?;谶@個特性,我們在需要修改一個功能實現(xiàn)的時候,可以通過實現(xiàn)一個新的子類的方式,在子類中重寫原來的功能邏輯,用子類代替父類。在實際的代碼運行過程中,調(diào)用子類新的功能邏輯,而不是在原有代碼上做修改。這就遵從了“對修改關閉、對擴展開放”的設計原則,提高了代碼的可擴展性。除此之外,利用多態(tài)特性,不同的類對象可以傳遞相同的方法,執(zhí)行不提供的代碼邏輯,提高了代碼的復用性。
所以所,基于四大特性,利用面向?qū)ο缶幊?,我們可以更輕松地寫出易復用、易擴展、易維護的代碼。
2.3 OOP 語言更加人性化、更加高級、更加智能
人類最早和計算機打交道是通過 0、1 這樣的二進制指令,然后是匯編語言,再之后才出現(xiàn)了高級編程語言。在高級編程語言中,面向過程編程語言又早于面向?qū)ο缶幊陶Z言出現(xiàn)。之所以先出現(xiàn)面向過程編程語言,那是因為和及其的交互方式,從二進制指令、匯編語言到面向過程編程語言,是一個非常自然的過渡,是一種流程化的、面條式的編程風格,用一組指令順序操作數(shù)據(jù),來完成一項任務。
從指令到匯編再到面向過程編程語言,跟機器打交道的方式在不停地進化,讓人和機器打交道越來越容易。面向?qū)ο缶幊陶Z言的出現(xiàn),也順應了這樣的發(fā)展規(guī)律,也就是說,面向?qū)ο缶幊陶Z言比面向過程編程語言更加高級。
面向?qū)ο缶幊陶Z言是一種人類的思維方式,在進行面向?qū)ο缶幊痰臅r候,我們在思考如何給業(yè)務建模,如何將真實的世界映射為類或?qū)ο螅@讓我們更加聚焦到業(yè)務本身,而不是思考如何跟機器打交道。文章來源:http://www.zghlxwxcb.cn/news/detail-836182.html
越高級的編程語言,離機器越遠,離人類越近,也越智能。文章來源地址http://www.zghlxwxcb.cn/news/detail-836182.html
到了這里,關于設計模式學習筆記 - 面向?qū)ο?- 3.面向?qū)ο蟊让嫦蜻^程有哪些優(yōu)勢?面向過程真的過時了嗎?的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!