概念
面向過程編程OPP:Procedure Oriented Programming,是一種以事物為中心的編程思想。主要關注“怎么做”,即完成任務的具體細節。
面向對象編程OOP:Object Oriented Programming,是一種以對象為基礎的編程思想。主要關注“誰來做”,即完成任務的對象。
面向切面編程AOP:Aspect Oriented Programming,基於OOP延伸出來的編程思想。主要實現的目的是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。
每種編程思想都有各自的優點,它們適用在不同的情況下:面向過程性能很高,面向對象比較易於管理和維護,面向切面使軟件變得更靈活。
新的編程范式,並不一定完全各方面都優於舊的編程范式,它們只是在某一特定領域或特殊場景下有着獨到的優勢。
編程范式只有適合不適合項目特性,沒有絕對的好壞。
OPP和OOP
面向過程是最為實際的一種思考方式,就算是面向對象的方法也是含有面向過程的思想。可以說面向過程是一種基礎的方法。它考慮的是實際地實現。一般的面向過程是從上往下步步求精,所以面向過程最重要的是模塊化的思想方法。當程序規模不是很大時,面向過程的方法還會體現出一種優勢。因為程序的流程很清楚,按着模塊與函數的方法可以很好的組織。
面向對象是基於對象概念,以對象為中心,以類和繼承為構造機制,來認識、理解、刻畫客觀世界和設計、構建相應的軟件系統。類和繼承是是適應人們一般思維方式的描述范式。方法是允許作用於該類對象上的各種操作。這種對象、類、消息和方法的程序設計范式的基本點在於對象的封裝性和類的繼承性。通過封裝能將對象的定義和對象的實現分開,通過繼承能體現類與類之間的關系,以及由此帶來的動態聯編和實體的多態性。
舉個栗子:
比如完成“吃飯”這個任務。
面向過程的寫法,需要封裝一個eat()函數:
如果是狗吃屎,則eat(狗,屎);
如果是人吃肉,則eat(人,肉);
eat是人和狗共用的吃飯本能。
那如果之后要處理貓吃魚、魚吃蝦、奧特曼吃小怪獸呢?eat函數中就會存在大量的if…else的判斷,這段代碼,無疑是很惡心的。
如果是面向對象思想,如何來解決這個問題呢?
我們發現,狗、人、貓、魚、奧特曼,都有一個“吃”的共性。我們抽象出每個受體的類,然后繼承,這樣都具有“吃”的方法。
當我們想要執行狗吃屎時,那就“狗->eat(屎)”,這樣,我們從面向過程維護eat()的焦點,轉移到了面向對象維護角色的焦點上來。我們只需要維護好不同的角色(類)就好了,並且狗的eat不會影響到貓的eat,貓的eat也不會影響到人的eat。
所以,oop思想非常貼近軟件工程高內聚的思想:自己管好自己的東西,自己做好自己的事情。
大多數支持面向對象的語言,同時也支持面向過程,不論是JAVA、PHP,還是JS,它們都還無法完全面向對象,因為面向過程是必然的,面向過程代表着必要的程序流程,調動對象進行組合或對象內部能力的實現,都一定會存在“過程”,它最終還是需要通過拆分步驟來指導最具體的執行細節。
在此,我們也能得到一些感悟,許多事情並非完全非黑即白,非OOP就必然是OPP,特別是思想層面的東西,它們呈現出互相結合的形態,從OPP到OOP,這是一個思想進步的過程。
AOP
面向切面編程主要實現的目的是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。
那么,AOP如何體現?
這里可以聯想一下laravel的中間件、javaweb的攔截器、vue的Decorator…它們都是AOP思想的實踐。裝飾器模式、代理模式,它們也是基於AOP思想的設計模式。
AOP思想,指導我們通過找到平整切面的形式,插入新的代碼,使新插入的代碼對切面上下原有流程的傷害降到最低。
舉個栗子:
我們拿laravel中間件做什么?
權限、日志、請求過濾、請求頻率限制、csrf過濾……
我們知道,中間件對於controller的業務邏輯,不會有任何傷害。
如果沒有這個切面,我們想要記錄請求日志,可能需要在每個controller的具體方法中寫日志記錄的代碼,或者調用日志記錄的函數、方法。
這會使一段記錄日志的代碼,或調用記錄日志的調用語句出現在許多controller中,這與controller原本要關注的邏輯無關,使controller職責不單一,提高維護成本。
當然,我們可能會寫一個父類,讓許多controller來繼承這個父類,然后統一在父類的__construct方法中記錄日志,以此來解決耦合問題。
但實際上,這個父類的construct方法,不正是一個切面嗎?它在原有流程中截取了一個切面,在切面中植入代碼,以達到承上啟下的作用,並且不對上下文產生傷害。
從這個例子中,我們也能得出另外一個思考:AOP指導我們尋找切面,但找到合適的切面,也尤為重要。就像上文,父類構造函數的切面和中間件的切面比起來,顯然中間件這個切面更利於維護,你可以靈活選擇中間件,但你無法靈活選擇父類,因為決定你的controller繼承什么父類的,不是切面中的代碼,而是controller本身處理什么邏輯。
許多項目,OPP、OOP、AOP是同時存在的,它們是編程范式,是一種指導編程的思想,並非不能互相配合。
本文從宏觀角度講解三種編程思想的異同點,旨在引領大家打個樣。具體到每個編程思想,其實還有很多深究的點,比如AOP思想,貫穿在很多設計模式中,比如代理模式、裝飾器模式、職責鏈模式……;學無止境啊,每天成長一點,終究不會錯的。