在Android開發(fā)領(lǐng)域,隨著應(yīng)用復(fù)雜度的攀升、多端協(xié)同需求的增加,以及用戶對(duì)流暢體驗(yàn)的高要求,“如何寫出易維護(hù)、可擴(kuò)展、低耦合的代碼”逐漸成為開發(fā)者面臨的核心挑戰(zhàn),而編程范式,作為編碼背后的“底層思維框架”,正是破解這一難題的關(guān)鍵,它不僅是抽象的理論概念,更是指導(dǎo)開發(fā)者設(shè)計(jì)架構(gòu)、組織代碼、處理數(shù)據(jù)流的“實(shí)戰(zhàn)工具”。
從早期Android開發(fā)中主導(dǎo)的面向?qū)ο缶幊蹋∣OP),到Jetpack?Compose生態(tài)下興起的函數(shù)式編程(FP),再到應(yīng)對(duì)異步場(chǎng)景的響應(yīng)式編程(Reactive?Programming)、解決橫切關(guān)注點(diǎn)的面向切面編程(AOP),每一種范式都對(duì)應(yīng)著特定的開發(fā)痛點(diǎn)與場(chǎng)景需求,本文將系統(tǒng)拆解Android開發(fā)中常用的編程范式,從核心定義、適用場(chǎng)景到典型實(shí)踐案例,幫助開發(fā)者理解不同范式的底層邏輯,掌握“在合適的場(chǎng)景選擇合適范式”的能力,最終實(shí)現(xiàn)從“能編碼”到“會(huì)設(shè)計(jì)”的進(jìn)階,為構(gòu)建高質(zhì)量Android應(yīng)用打下堅(jiān)實(shí)基礎(chǔ)。
知識(shí)點(diǎn)匯總:

一:什么是編程范式
編程范式是一種編程思想的總稱,它是指在編寫程序時(shí)所采用的基本方法和規(guī)范,常見的編程范式有面向?qū)ο?、函?shù)式、邏輯式等,選擇合適的編程范式可以提高代碼的可讀性、可維護(hù)性和可擴(kuò)展性。
二:常見的編程范式
命令式編程(Imperative?Programming):以指令的形式描述計(jì)算機(jī)執(zhí)行的具體步驟,關(guān)注計(jì)算機(jī)的狀態(tài)變化和控制流程,典型代表語言:C、Java、kotlin。
面向?qū)ο缶幊蹋∣bject-Oriented?Programming):將程序組織為對(duì)象的集合,強(qiáng)調(diào)數(shù)據(jù)和操作的封裝、繼承和多態(tài),典型代表語言:Java、C++、Python、kotlin。
函數(shù)式編程(Functional?Programming):將計(jì)算視為數(shù)學(xué)函數(shù)的求值,強(qiáng)調(diào)使用純函數(shù)、不可變數(shù)據(jù)和高階函數(shù),典型代表語言:kotlin、Haskell、Clojure、Scala。
聲明式編程(Declarative?Programming):以描述問題的本質(zhì)和解決方案的邏輯為重點(diǎn),而非具體的計(jì)算步驟,典型代表語言:Prolog、SQL、HTML/CSS。
邏輯編程(Logic?Programming):使用邏輯表達(dá)式描述問題和解決方案,基于邏輯推理進(jìn)行計(jì)算,典型代表語言:Prolog。
并發(fā)編程(Concurrent?Programming):處理多個(gè)并發(fā)執(zhí)行的任務(wù),關(guān)注并發(fā)、并行、同步和通信等問題,典型代表語言:Java、Go、Erlang、kotlin。
通用編程(Generic?Programming):通過參數(shù)化類型來實(shí)現(xiàn)代碼的復(fù)用和抽象,提供通用的數(shù)據(jù)結(jié)構(gòu)和算法,典型代表語言:C++、Rust。
面向切面編程(Aspect-Oriented?Programming):將橫切關(guān)注點(diǎn)(如日志、事務(wù)管理)從主要邏輯中分離出來,以提供更好的模塊化和可維護(hù)性,典型代表框架:AspectJ。
響應(yīng)式編程(Reactive?Programming):通過使用流(Stream)和異步事件來處理數(shù)據(jù)流和事件流,使程序能夠以響應(yīng)式、彈性和容錯(cuò)的方式進(jìn)行處理,典型代表框架:RxJava、Reactor。
三:常見編程范式圖解


這些編程范式具有不同的思維方式、原則和技術(shù),適用于不同的問題和場(chǎng)景,在實(shí)際開發(fā)中,可以根據(jù)需求和團(tuán)隊(duì)的偏好選擇合適的編程范式或結(jié)合多種范式來實(shí)現(xiàn)目標(biāo),需要注意的是,并非每種編程語言都完全支持所有編程范式,有些語言可能更加傾向于某種特定的范式,此外,隨著技術(shù)的發(fā)展,新的編程范式也在不斷涌現(xiàn),擴(kuò)展了編程的思維和能力,下面會(huì)根據(jù)Android項(xiàng)目使用情況,不同程度解析各種編程范式。
四:編程范式之于Android
一:面向?qū)ο缶幊?/h4>
面向?qū)ο缶幊蹋∣bject-Oriented?Programming,OOP)是一種基于對(duì)象的編程范式,它將現(xiàn)實(shí)世界中的事物抽象成對(duì)象,并通過對(duì)象之間的交互來實(shí)現(xiàn)程序的設(shè)計(jì)和開發(fā),在面向?qū)ο缶幊讨校绦虻暮诵乃枷胧峭ㄟ^定義類、創(chuàng)建對(duì)象、定義對(duì)象之間的關(guān)系和交互來構(gòu)建軟件系統(tǒng),將數(shù)據(jù)(屬性)和行為(方法)封裝為對(duì)象,通過類定義模板,利用繼承、多態(tài)實(shí)現(xiàn)復(fù)用與擴(kuò)展,強(qiáng)調(diào) “模塊化”,面向?qū)ο缶幊倘蠛诵奶匦裕悍庋b、繼承、多態(tài),實(shí)現(xiàn)對(duì)現(xiàn)實(shí)世界實(shí)體的抽象建模,構(gòu)建靈活、可維護(hù)、可擴(kuò)展的軟件系統(tǒng),三者相互支撐,共同構(gòu)成面向?qū)ο笏枷氲暮诵目蚣堋?/p>
封裝(Encapsulation)
1、定義??
封裝是指將對(duì)象的數(shù)據(jù)(屬性)與操作數(shù)據(jù)的行為(方法)捆綁為一個(gè)有機(jī)整體,并通過訪問控制機(jī)制隱藏對(duì)象內(nèi)部的實(shí)現(xiàn)細(xì)節(jié),僅對(duì)外暴露有限的、標(biāo)準(zhǔn)化的接口供外部交互,即“隱藏內(nèi)部細(xì)節(jié),暴露必要接口”。
2、核心體現(xiàn)??
數(shù)據(jù)與行為的捆綁:將描述對(duì)象特征的屬性(如“人”的姓名、年齡)與操作這些屬性的方法(如“人”的吃飯、行走方法)封裝在同一個(gè)類中,形成邏輯上的獨(dú)立單元。??
訪問控制:通過訪問修飾符(如public、private、protected等)限制外部對(duì)內(nèi)部數(shù)據(jù)的直接操作,僅允許通過預(yù)定義的方法(如getter/setter)訪問或修改數(shù)據(jù),確保數(shù)據(jù)操作的合法性(如年齡不能為負(fù)數(shù))。??
實(shí)現(xiàn)細(xì)節(jié)隱藏:外部無需了解對(duì)象內(nèi)部的邏輯(如“計(jì)算工資”的具體算法),只需通過接口(如calculateSalary()方法)調(diào)用功能,降低外部對(duì)內(nèi)部實(shí)現(xiàn)的依賴。
3、目標(biāo)價(jià)值??
保障數(shù)據(jù)安全性:防止外部隨意修改對(duì)象內(nèi)部狀態(tài),避免數(shù)據(jù)被非法篡改或處于不一致狀態(tài)。??
提升模塊獨(dú)立性:對(duì)象內(nèi)部邏輯的修改(如優(yōu)化算法)不影響外部調(diào)用者,降低系統(tǒng)耦合度。??
簡(jiǎn)化交互復(fù)雜度:外部?jī)H需關(guān)注接口功能,無需理解內(nèi)部實(shí)現(xiàn),降低使用成本。
繼承(Inheritance)
1、定義??
繼承是指子類(派生類)通過某種機(jī)制獲取父類(基類)的屬性與方法,并在此基礎(chǔ)上擴(kuò)展新的屬性或重寫父類方法,形成類之間的層次化關(guān)系,實(shí)現(xiàn)“復(fù)用已有邏輯,擴(kuò)展新功能”。
2、核心體現(xiàn)??
代碼復(fù)用:子類無需重復(fù)定義父類已有的屬性和方法(如“學(xué)生”類繼承“人”類的“姓名”“年齡”屬性和“呼吸”方法),直接復(fù)用父類邏輯。??
功能擴(kuò)展:子類可在繼承父類的基礎(chǔ)上添加新的屬性或方法(如“學(xué)生”類新增“學(xué)號(hào)”屬性和“上課”方法),實(shí)現(xiàn)對(duì)父類功能的橫向擴(kuò)展。??
方法重寫:子類可根據(jù)自身需求重寫父類的方法(如“鳥”類繼承“動(dòng)物”類的“移動(dòng)”方法,但將其實(shí)現(xiàn)為“飛行”而非“行走”),體現(xiàn)個(gè)性邏輯。??
層次化建模:通過繼承構(gòu)建類的樹形結(jié)構(gòu)(如“生物”→“動(dòng)物”→“哺乳動(dòng)物”→“人類”),反映現(xiàn)實(shí)世界中事物的分類關(guān)系。
3、目標(biāo)價(jià)值??
減少代碼冗余:通過復(fù)用父類邏輯,避免相同代碼在多個(gè)類中重復(fù)編寫,提升開發(fā)效率。??
增強(qiáng)系統(tǒng)一致性:同一父類的子類共享基礎(chǔ)邏輯(如“所有動(dòng)物都有生命”),保證系統(tǒng)設(shè)計(jì)的統(tǒng)一性。??
支持增量開發(fā):基于已有類擴(kuò)展新類,無需修改原有代碼,符合“開放-封閉原則”(對(duì)擴(kuò)展開放,對(duì)修改封閉)。
多態(tài)(Polymorphism)
1、定義??
多態(tài)是指同一操作(如方法調(diào)用)作用于不同對(duì)象時(shí),會(huì)根據(jù)對(duì)象的具體類型產(chǎn)生不同的執(zhí)行結(jié)果,即“同一接口,多種實(shí)現(xiàn)”,其核心是通過接口抽象或繼承關(guān)系,使程序在運(yùn)行時(shí)動(dòng)態(tài)綁定具體實(shí)現(xiàn)。
2、核心體現(xiàn)??
接口多實(shí)現(xiàn):多個(gè)類實(shí)現(xiàn)同一接口(或繼承同一父類),并重寫接口中的方法,使接口的同一方法具有不同實(shí)現(xiàn)(如“支付接口”可被“微信支付”“支付寶”類分別實(shí)現(xiàn)為不同的支付邏輯)。??
動(dòng)態(tài)綁定:程序編譯時(shí)引用的是父類或接口類型,運(yùn)行時(shí)實(shí)際執(zhí)行的是子類的具體實(shí)現(xiàn)(如聲明Payment?pay?=?new?WechatPay(),調(diào)用pay.pay()時(shí)執(zhí)行微信支付邏輯)。??
行為適配:同一操作根據(jù)上下文自動(dòng)適配不同對(duì)象(如“打印”操作,對(duì)“文本文件”打印文字內(nèi)容,對(duì)“圖片文件”打印圖像預(yù)覽)。
3、目標(biāo)價(jià)值??
提升代碼靈活性:通過統(tǒng)一接口操作不同對(duì)象,無需針對(duì)每個(gè)對(duì)象編寫單獨(dú)邏輯(如用List接口統(tǒng)一操作ArrayList、LinkedList,無需關(guān)心具體實(shí)現(xiàn)類)。??
增強(qiáng)系統(tǒng)可擴(kuò)展性:新增功能時(shí)只需實(shí)現(xiàn)接口或繼承父類,無需修改原有調(diào)用邏輯(如新增“銀聯(lián)支付”類,原有pay()調(diào)用代碼無需改動(dòng))。??
簡(jiǎn)化邏輯設(shè)計(jì):通過抽象接口屏蔽具體實(shí)現(xiàn)差異,使代碼更聚焦于“做什么”而非“怎么做”,降低系統(tǒng)復(fù)雜度。
三大特性的協(xié)同關(guān)系:??
封裝是面向?qū)ο蟮幕A(chǔ),通過隱藏細(xì)節(jié)、暴露接口為繼承和多態(tài)提供了可靠的交互邊界,繼承通過代碼復(fù)用與層次化關(guān)系,為多態(tài)提供了實(shí)現(xiàn)載體(子類對(duì)父類方法的重寫),多態(tài)則通過統(tǒng)一接口與動(dòng)態(tài)綁定,最大化發(fā)揮封裝的模塊化優(yōu)勢(shì)和繼承的擴(kuò)展能力,三者共同作用,使面向?qū)ο缶幊棠軌驑?gòu)建出更貼近現(xiàn)實(shí)世界、更易維護(hù)和擴(kuò)展的軟件系統(tǒng)。
面向?qū)ο蟮脑O(shè)計(jì)原則:
在Android開發(fā)中,面向?qū)ο蟮脑O(shè)計(jì)原則是構(gòu)建可維護(hù)、可擴(kuò)展架構(gòu)的核心思想,它們并非強(qiáng)制規(guī)范,而是經(jīng)過實(shí)踐驗(yàn)證的最佳實(shí)踐,能有效解決代碼耦合、擴(kuò)展性差等問題,以下是結(jié)合Android場(chǎng)景的詳細(xì)解析:
單一職責(zé)原則(Single?Responsibility?Principle,SRP)
概念:一個(gè)類應(yīng)該只負(fù)責(zé)一項(xiàng)職責(zé)(或一個(gè)功能領(lǐng)域),即一個(gè)類只有一個(gè)引起它變化的原因。??
核心目標(biāo):降低類的復(fù)雜度,提高可讀性和可維護(hù)性。??
Android場(chǎng)景示例:??
反例:在MainActivity中同時(shí)處理UI更新、網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)存儲(chǔ)邏輯,導(dǎo)致類臃腫(上千行代碼),修改網(wǎng)絡(luò)邏輯可能影響UI展示。??
正例:按職責(zé)拆分:??
MainActivity:僅負(fù)責(zé)UI交互(如按鈕點(diǎn)擊、TextView更新)。??
UserViewModel:處理業(yè)務(wù)邏輯(如數(shù)據(jù)轉(zhuǎn)換、狀態(tài)管理)。??
UserRepository:負(fù)責(zé)數(shù)據(jù)獲取(網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)庫(kù)操作)。??
代碼實(shí)現(xiàn):
// 符合單一職責(zé)的代碼結(jié)構(gòu)
class MainActivity : AppCompatActivity() {
????private val viewModel: UserViewModel by viewModels()
????override fun onCreate(savedInstanceState: Bundle?) {
????????super.onCreate(savedInstanceState)
????????setContentView(R.layout.activity_main)
????????// 僅處理UI交互
????????btnLoad.setOnClickListener { viewModel.loadUser() }
????????viewModel.user.observe(this) { tvName.text = it.name }
????}
}
class UserViewModel(private val repo: UserRepository) : ViewModel() {
????val user = MutableLiveData<User>()
????// 僅處理業(yè)務(wù)邏輯
????fun loadUser() {
????????viewModelScope.launch {
????????????user.value = repo.fetchUser()
????????}
????}
}
class UserRepository(private val api: UserApi) {
????// 僅負(fù)責(zé)數(shù)據(jù)獲取
????suspend fun fetchUser() = api.getUser()
}
開閉原則(Open-Closed?Principle,OCP)
概念:軟件實(shí)體(類、模塊、函數(shù)等)對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉,即新增功能時(shí),應(yīng)通過擴(kuò)展現(xiàn)有代碼實(shí)現(xiàn),而非修改原有代碼。??
核心目標(biāo):避免修改已有代碼導(dǎo)致的風(fēng)險(xiǎn)(如引入新bug)。??
Android場(chǎng)景示例:??
需求:App需要支持“微信支付”和“支付寶支付”,未來可能新增“銀聯(lián)支付”。??
反例:在PayManager中用if-else判斷支付類型,新增支付方式需修改PayManager。??
正例:定義抽象支付接口,通過新增實(shí)現(xiàn)類擴(kuò)展功能:??
代碼實(shí)現(xiàn):
//?1.?定義抽象接口(對(duì)擴(kuò)展開放)
interface?Payment?{
????fun?pay(amount:?Double)
}
//?2.?實(shí)現(xiàn)具體支付方式
class?WechatPayment?:?Payment?{
????override?fun?pay(amount:?Double)?{
????????//?微信支付邏輯
????}
}
class?AlipayPayment?:?Payment?{
????override?fun?pay(amount:?Double)?{
????????//?支付寶支付邏輯
????}
}
//?3.?支付管理類(對(duì)修改關(guān)閉,無需改動(dòng)即可支持新支付方式)
class?PayManager(private?val?payment:?Payment)?{
????fun?processPayment(amount:?Double)?{
????????payment.pay(amount)?//?依賴抽象,不依賴具體實(shí)現(xiàn)
????}
}
//?使用:新增銀聯(lián)支付只需添加UnionPayPayment實(shí)現(xiàn)類,無需修改PayManager
val?unionPay?=?UnionPayPayment()
val?payManager?=?PayManager(unionPay)
payManager.processPayment(100.0)
里氏替換原則(Liskov?Substitution?Principle,LSP)
概念:所有引用父類的地方,必須能透明地替換為其子類對(duì)象,且程序行為不變,即子類不能破壞父類的行為約定。??
核心目標(biāo):保證繼承關(guān)系的合理性,避免子類“重寫”父類方法時(shí)引入異常邏輯。??
Android場(chǎng)景示例:??
反例:父類Bird有fly()方法,子類Penguin(企鵝)重寫fly()時(shí)拋出“不能飛”的異常,導(dǎo)致調(diào)用Bird.fly()的地方崩潰。??
正例:重構(gòu)繼承關(guān)系,將“會(huì)飛的鳥”抽象為FlyingBird,企鵝直接繼承Bird(不含fly()):??
代碼實(shí)現(xiàn):
//?父類:鳥(不定義fly(),因?yàn)椴⒎撬续B都會(huì)飛)
open?class?Bird?{
????open?fun?eat()?{?/*?吃東西邏輯?*/?}
}
//?子類:會(huì)飛的鳥(擴(kuò)展出fly())
open?class?FlyingBird?:?Bird()?{
????open?fun?fly()?{?/*?飛行邏輯?*/?}
}
//?具體實(shí)現(xiàn):麻雀(會(huì)飛)
class?Sparrow?:?FlyingBird()?{
????override?fun?fly()?{?/*?麻雀飛行?*/?}
}
//?具體實(shí)現(xiàn):企鵝(不會(huì)飛,直接繼承Bird)
class?Penguin?:?Bird()?{
????//?無需實(shí)現(xiàn)fly(),避免違反里氏替換
}
//?使用:調(diào)用FlyingBird的地方,替換為Sparrow完全兼容
fun?letBirdFly(bird:?FlyingBird)?{
????bird.fly()?//?傳入Sparrow正常執(zhí)行,不會(huì)出現(xiàn)異常
}
依賴倒置原則(Dependency?Inversion?Principle,DIP)
概念:高層模塊不依賴低層模塊,兩者都依賴抽象,抽象不依賴細(xì)節(jié),細(xì)節(jié)依賴抽象。??
核心目標(biāo):通過抽象隔離高層與低層模塊,降低耦合(高層無需關(guān)心低層具體實(shí)現(xiàn))。??
Android場(chǎng)景示例:??
反例:UserViewModel直接依賴RetrofitUserApi(低層具體實(shí)現(xiàn)),若后期替換為MockUserApi,需修改UserViewModel。??
正例:引入抽象接口UserApi,ViewModel依賴接口,具體實(shí)現(xiàn)由外部注入:??
代碼實(shí)現(xiàn):
//?1.?定義抽象接口(抽象)
interface?UserApi?{
????suspend?fun?getUser():?User
}
//?2.?低層實(shí)現(xiàn)(細(xì)節(jié))
class?RetrofitUserApi?:?UserApi?{
????override?suspend?fun?getUser()?=?/*?Retrofit網(wǎng)絡(luò)請(qǐng)求?*/
}
class?MockUserApi?:?UserApi?{
????override?suspend?fun?getUser()?=?User("測(cè)試用戶")?//?模擬數(shù)據(jù)
}
//?3.?高層模塊(ViewModel)依賴抽象,不依賴具體實(shí)現(xiàn)
class?UserViewModel(private?val?api:?UserApi)?:?ViewModel()?{
????//?僅調(diào)用api.getUser(),無需關(guān)心是Retrofit還是Mock實(shí)現(xiàn)
}
//?使用:通過構(gòu)造函數(shù)注入具體實(shí)現(xiàn),高層模塊無需修改
val?viewModel?=?UserViewModel(RetrofitUserApi())?//?生產(chǎn)環(huán)境
val?testViewModel?=?UserViewModel(MockUserApi())?//?測(cè)試環(huán)境
接口隔離原則(Interface?Segregation?Principle,ISP)
概念:客戶端不應(yīng)依賴它不需要的接口,即一個(gè)接口應(yīng)盡可能?。ㄖ话蛻舳诵枰姆椒ǎ苊狻芭纸涌凇?。??
核心目標(biāo):減少接口冗余,防止客戶端被迫實(shí)現(xiàn)不需要的方法。??
Android場(chǎng)景示例:??
反例:定義Player接口包含playMusic()、playVideo()、recordAudio(),音樂播放器MusicPlayer被迫實(shí)現(xiàn)不需要的playVideo()(空實(shí)現(xiàn)或拋異常)。??
正例:拆分接口為專用接口:??
代碼實(shí)現(xiàn):
//?拆分后的專用接口
interface?MusicPlayer?{
????fun?playMusic()
????fun?pauseMusic()
}
interface?VideoPlayer?{
????fun?playVideo()
????fun?pauseVideo()
}
interface?AudioRecorder?{
????fun?recordAudio()
}
//?音樂播放器只需實(shí)現(xiàn)MusicPlayer
class?SimpleMusicPlayer?:?MusicPlayer?{
????override?fun?playMusic()?{?/*?播放音樂?*/?}
????override?fun?pauseMusic()?{?/*?暫停音樂?*/?}
????//?無需關(guān)心視頻或錄音方法
}
//?多媒體播放器可實(shí)現(xiàn)多個(gè)接口
class?MediaPlayer?:?MusicPlayer,?VideoPlayer?{
????override?fun?playMusic()?{?/*?播放音樂?*/?}
????override?fun?pauseMusic()?{?/*?暫停音樂?*/?}
????override?fun?playVideo()?{?/*?播放視頻?*/?}
????override?fun?pauseVideo()?{?/*?暫停視頻?*/?}
}
迪米特法則(Law?of?Demeter,LoD)
概念:一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象保持最少的了解(“只與直接朋友通信”),直接朋友指:成員變量、方法參數(shù)、返回值中的對(duì)象,避免訪問“朋友的朋友”。??
核心目標(biāo):減少對(duì)象間的交互,降低耦合。??
Android場(chǎng)景示例:??
反例:Activity通過ViewModel獲取Repository,再調(diào)用Repository的api方法(訪問了“朋友的朋友”)。??
正例:ViewModel封裝Repository的操作,Activity僅與ViewModel交互:??
代碼實(shí)現(xiàn):
//?反例:違反迪米特法則
class?BadActivity?:?AppCompatActivity()?{
????private?val?viewModel:?UserViewModel?by?viewModels()
????fun?loadUser()?{
????????//?直接訪問viewModel的repo的api,超出了直接朋友關(guān)系
????????val?user?=?viewModel.repo.api.getUser()?
????}
}
//?正例:符合迪米特法則
class?GoodActivity?:?AppCompatActivity()?{
????private?val?viewModel:?UserViewModel?by?viewModels()
????fun?loadUser()?{
????????//?僅與直接朋友viewModel交互,不關(guān)心其內(nèi)部依賴
????????viewModel.loadUser()?
????}
}
class?UserViewModel(private?val?repo:?UserRepository)?:?ViewModel()?{
????//?封裝內(nèi)部邏輯,對(duì)外提供簡(jiǎn)潔接口
????fun?loadUser()?{
????????repo.fetchUser()?//?內(nèi)部訪問repo,外部無需關(guān)心
????}
}
合成復(fù)用原則(Composite?Reuse?Principle,CRP)
概念:優(yōu)先使用組合(has-a)或聚合(contains-a)關(guān)系實(shí)現(xiàn)代碼復(fù)用,而非繼承(is-a)。??
核心目標(biāo):避免繼承帶來的緊耦合(父類修改影響所有子類),提高靈活性。??
Android場(chǎng)景示例:??
反例:ShareManager繼承WechatShare實(shí)現(xiàn)微信分享,后期需支持微博分享,需修改繼承關(guān)系為WeiboShare,違反開閉原則。??
正例:通過組合實(shí)現(xiàn),ShareManager持有不同分享器的引用:??
代碼實(shí)現(xiàn):
//?1.?定義分享接口
interface?Shareable?{
????fun?share(content:?String)
}
//?2.?具體分享實(shí)現(xiàn)
class?WechatShare?:?Shareable?{
????override?fun?share(content:?String)?{?/*?微信分享?*/?}
}
class?WeiboShare?:?Shareable?{
????override?fun?share(content:?String)?{?/*?微博分享?*/?}
}
//?3.?通過組合復(fù)用,而非繼承
class?ShareManager(
????private?val?wechat:?Shareable,
????private?val?weibo:?Shareable
)?{
????fun?shareToWechat(content:?String)?=?wechat.share(content)
????fun?shareToWeibo(content:?String)?=?weibo.share(content)
}
//?使用:靈活替換分享實(shí)現(xiàn)
val?shareManager?=?ShareManager(WechatShare(),?WeiboShare())
shareManager.shareToWechat("Hello")
控制反轉(zhuǎn)(Inversion of Control,IOC)原則
概念:將對(duì)象的創(chuàng)建、依賴管理的控制權(quán)從代碼內(nèi)部轉(zhuǎn)移到外部容器(如框架),即“誰控制誰?控制什么?為何反轉(zhuǎn)?”。??
傳統(tǒng)方式:類主動(dòng)new依賴對(duì)象(如Activity中val?repo?=?UserRepository()),控制權(quán)在類內(nèi)部。??
IOC方式:外部容器(如Hilt)創(chuàng)建依賴并“注入”到類中,控制權(quán)在外部。??
核心目標(biāo):解耦對(duì)象依賴,讓類更專注于自身業(yè)務(wù),而非依賴的創(chuàng)建。??
IOC在Android中的實(shí)現(xiàn):依賴注入(DI)
IOC是思想,依賴注入(DI)是其主要實(shí)現(xiàn)方式,Android中常用框架:Hilt(官方推薦)、Koin。??
代碼實(shí)現(xiàn):(Hilt實(shí)現(xiàn)IOC示例)
//?1.?定義可注入的依賴(由Hilt容器管理)
class?UserRepository?@Inject?constructor(
????private?val?api:?UserApi?//?依賴由Hilt注入
)?{
????suspend?fun?fetchUser()?=?api.getUser()
}
//?2.?提供接口實(shí)現(xiàn)(告訴Hilt如何創(chuàng)建UserApi)
@Module
@InstallIn(SingletonComponent::class)
object?NetworkModule?{
????@Provides
????@Singleton
????fun?provideUserApi():?UserApi?{
????????return?Retrofit.Builder()
.baseUrl("https://api.example.com/")
????????????.build()
????????????.create(UserApi::class.java)
????}
}
//?3.?在Activity中注入依賴(無需手動(dòng)創(chuàng)建)
@AndroidEntryPoint
class?MainActivity?:?AppCompatActivity()?{
????@Inject
????lateinit?var?repository:?UserRepository?//?控制權(quán)在Hilt,而非Activity
????override?fun?onCreate(savedInstanceState:?Bundle?)?{
????????super.onCreate(savedInstanceState)
????????//?直接使用注入的依賴
????????lifecycleScope.launch?{
????????????val?user?=?repository.fetchUser()
????????}
????}
}
IOC與依賴倒置的關(guān)系:??
依賴倒置(DIP)是原則:要求依賴抽象。??
IOC是實(shí)現(xiàn)DIP的手段:通過容器注入抽象的具體實(shí)現(xiàn),讓高層模塊無需依賴低層細(xì)節(jié)。??
設(shè)計(jì)原則總結(jié):
這些原則的核心目標(biāo)一致:降低耦合、提高復(fù)用、增強(qiáng)擴(kuò)展,在Android開發(fā)中,單一職責(zé)、迪米特法則解決類的“邊界”問題,避免臃腫,開閉、里氏替換、接口隔離保證擴(kuò)展靈活性,適應(yīng)需求變化,依賴倒置、IOC:解決模塊間依賴關(guān)系,支撐大型項(xiàng)目架構(gòu)(如MVVM+模塊化)合成復(fù)用:平衡復(fù)用與耦合,比繼承更靈活,實(shí)際開發(fā)中無需教條遵守所有原則,需根據(jù)場(chǎng)景權(quán)衡(如小型工具類可適當(dāng)放寬單一職責(zé)),但大型項(xiàng)目(如電商App、車載系統(tǒng))嚴(yán)格遵循可顯著降低維護(hù)成本。
代碼實(shí)現(xiàn)面向?qū)ο缶幊痰奶攸c(diǎn):
//?定義一個(gè)汽車類
class?Car?{
????private?String?brand;
????private?String?color;
????public?Car(String?brand,?String?color)?{
????????this.brand?=?brand;
????????this.color?=?color;
????}
????public?void?start()?{
????????System.out.println("The?"?+?color?+?"?"?+?brand?+?"?car?starts.");
????}
????public?void?stop()?{
????????System.out.println("The?"?+?color?+?"?"?+?brand?+?"?car?stops.");
????}
}
public?class?OOPExample?{
????public?static?void?main(String[]?args)?{
????????//?創(chuàng)建一個(gè)Car對(duì)象
????????Car?myCar?=?new?Car("Toyota",?"Red");
????????//?調(diào)用對(duì)象的方法
????????myCar.start();
????????myCar.stop();
????}
}
在上面的示例中,我們定義了一個(gè)Car類,它具有品牌和顏色屬性,并且具有start()和stop()方法用于啟動(dòng)和停止汽車在main()方法中,我們創(chuàng)建了一個(gè)Car對(duì)象myCar,并調(diào)用了其方法來啟動(dòng)和停止汽車,這個(gè)示例展示了面向?qū)ο缶幊痰奶攸c(diǎn),即通過定義類和創(chuàng)建對(duì)象來實(shí)現(xiàn)程序的設(shè)計(jì)和開發(fā),具體步驟如下:
1、定義一個(gè)Car類,它具有品牌和顏色屬性,并且定義了start()和stop()方法。
2、在main()方法中,通過new關(guān)鍵字創(chuàng)建一個(gè)Car對(duì)象myCar,并傳遞品牌和顏色參數(shù)。
3、調(diào)用myCar對(duì)象的start()和stop()方法來啟動(dòng)和停止汽車。
優(yōu)點(diǎn):
模塊化:通過將功能封裝在對(duì)象中,實(shí)現(xiàn)了代碼的模塊化和重用。
繼承與多態(tài):通過繼承和多態(tài)的機(jī)制,實(shí)現(xiàn)了代碼的擴(kuò)展和靈活性。
封裝與信息隱藏:通過將數(shù)據(jù)和方法封裝在對(duì)象中,提高了代碼的安全性和可維護(hù)性。
可維護(hù)性:面向?qū)ο缶幊痰拇a通常更易于理解、調(diào)試和維護(hù)。
挑戰(zhàn)和缺點(diǎn):
學(xué)習(xí)曲線:面向?qū)ο缶幊痰母拍詈驮瓌t需要一定的學(xué)習(xí)和理解。
性能開銷:面向?qū)ο缶幊痰撵`活性和封裝性可能導(dǎo)致一定的性能開銷。
設(shè)計(jì)復(fù)雜性:設(shè)計(jì)良好的面向?qū)ο笙到y(tǒng)需要合理的類和對(duì)象設(shè)計(jì),這可能增加系統(tǒng)的復(fù)雜性。
總的來說,面向?qū)ο缶幊淌且环N強(qiáng)大的編程范式,它提供了豐富的工具和概念來構(gòu)建靈活、可擴(kuò)展和可維護(hù)的軟件系統(tǒng)。
二:面向切面編程
AOP:面向切面編程(Aspect-Oriented?Programming)?是一種用于解決橫切關(guān)注點(diǎn)的模塊化問題的編程范式,橫切關(guān)注點(diǎn)是指跨越應(yīng)用程序多個(gè)模塊的功能,例如日志記錄、性能監(jiān)測(cè)、事務(wù)管理等,AOP通過將橫切關(guān)注點(diǎn)從主要業(yè)務(wù)邏輯中分離出來,使得代碼更加模塊化、可維護(hù)性更高,如果說,OOP如果是把問題劃分到單個(gè)模塊的話,那么AOP就是把涉及到眾多模塊的某一類問題進(jìn)行統(tǒng)一管理,AOP就是通過預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù),利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,提高開發(fā)效率。
OOP與AOP的區(qū)別:
一、編程思想不同
AOP:面向切面編程,是一種編程思想,它主要關(guān)注的是程序中跨多個(gè)模塊的關(guān)注點(diǎn),也就是所謂的”切面”,它的主要目的是將處理這些關(guān)注點(diǎn)的代碼從業(yè)務(wù)邏輯中分離出來,以提高程序的可重用性和可維護(hù)性。
OOP:面向?qū)ο缶幊蹋且环N基于”對(duì)象”概念的編程方法,它將數(shù)據(jù)和對(duì)數(shù)據(jù)的操作封裝在對(duì)象中,以提高代碼的復(fù)用性、模塊性和易讀性。
二、處理程序復(fù)雜性的方法不同
AOP:面向切面編程的方法是將那些散布在各個(gè)業(yè)務(wù)邏輯中的公共功能抽取出來,形成”切面”,然后通過預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一管理。
OOP:面向?qū)ο缶幊痰姆椒ㄊ菍?fù)雜的問題抽象化,通過類和對(duì)象將數(shù)據(jù)和處理數(shù)據(jù)的方法組織起來,實(shí)現(xiàn)問題的模塊化和層次化。
三、代碼的組織方式不同
AOP:在面向切面編程中,代碼被劃分為核心關(guān)注點(diǎn)和橫切關(guān)注點(diǎn),核心關(guān)注點(diǎn)通過業(yè)務(wù)模塊實(shí)現(xiàn),橫切關(guān)注點(diǎn)通過切面實(shí)現(xiàn)。
OOP:在面向?qū)ο缶幊讨?,代碼被組織為一個(gè)個(gè)的類和對(duì)象,通過類的實(shí)例化形成對(duì)象,對(duì)象通過消息傳遞進(jìn)行交互。
四、應(yīng)用場(chǎng)景不同
AOP:面向切面編程主要應(yīng)用于處理一些公共任務(wù),如日志記錄、事務(wù)處理、權(quán)限校驗(yàn)等。
OOP:面向?qū)ο缶幊讨饕獞?yīng)用于業(yè)務(wù)邏輯的實(shí)現(xiàn),特別是在需要大量復(fù)用代碼的情況下。
下面我們看看通過面向切面編程技術(shù),在源碼的不同階段實(shí)現(xiàn)對(duì)代碼的注入圖:

APT:
代表框架:ARouter、DataBinding、Dagger2、ButterKnife、EventBus3、DBFlow、AndroidAnnotation
注解處理器Java5中叫APT(Annotation?Processing?Tool),在Java6開始,規(guī)范化為Pluggable?Annotation?Processing,Apt應(yīng)該是這其中我們最常見到的了,難度也最低,定義編譯期的注解,再通過繼承Proccesor實(shí)現(xiàn)代碼生成邏輯,實(shí)現(xiàn)了編譯期生成代碼的邏輯。
難點(diǎn):
就apt本身來說沒有任何難點(diǎn)可言,難點(diǎn)一:在于設(shè)計(jì)模式和解耦思想的靈活應(yīng)用,難點(diǎn)二:在于代碼生成的繁瑣,你可以手動(dòng)字符串拼接,當(dāng)然有更高級(jí)的玩法用squareup的javapoet,用建造者的模式構(gòu)建出任何你想要的源代碼。
優(yōu)點(diǎn):
它的強(qiáng)大之處無需多言,看代表框架的源碼,你可以學(xué)到很多新姿勢(shì),總的一句話:它可以做任何你不想做的繁雜的工作,它可以幫你寫任何你不想重復(fù)代碼。
AspectJ:
代表框架:?Hugo(Jake?Wharton)
AspectJ支持編譯期和加載時(shí)代碼注入,在開始之前,我們先看看需要了解的詞匯:
Advice(通知):?典型的Advice類型有before、after和around,分別表示在目標(biāo)方法執(zhí)行之前、執(zhí)行后和完全替代目標(biāo)方法執(zhí)行的代碼。
Joint?point(連接點(diǎn)):?程序中可能作為代碼注入目標(biāo)的特定的點(diǎn)和入口。
Pointcut(切入點(diǎn)):?告訴代碼注入工具,在何處注入一段特定代碼的表達(dá)式。
Aspect(切面):?Pointcut和Advice的組合看做切面,例如,在本例中通過定義一個(gè)pointcut和給定恰當(dāng)?shù)腶dvice,添加一個(gè)了內(nèi)存緩存的切面。
Weaving(織入):?注入代碼(advices)到目標(biāo)位置(joint?points)的過程。
下面這張圖簡(jiǎn)要總結(jié)了一下上述這些概念:

難點(diǎn):
AspectJ語法比較多,但是掌握幾個(gè)簡(jiǎn)單常用的,就能實(shí)現(xiàn)絕大多數(shù)切片,完全兼容Java(純Java語言開發(fā),然后使用AspectJ注解,簡(jiǎn)稱@AspectJ。)
優(yōu)點(diǎn):
AspectJ除了hook之外,AspectJ還可以為目標(biāo)類添加變量和接口,另外,AspectJ也有抽象,繼承等各種更高級(jí)的玩法,它能夠在編譯期間直接修改源代碼生成class,強(qiáng)大的團(tuán)戰(zhàn)切入功能,指哪打哪,鞭辟入里。
Javassist:
代表框架:熱修復(fù)框架HotFix?、Savior(InstantRun)
Javassist作用是在編譯其間修改class文件,與之相似的ASM(熱修復(fù)框架女媧)也有這個(gè)功能,可以讓我們直接修改編譯后的class二進(jìn)制代碼,首先我們得知道什么時(shí)候編譯完成,并且我們要趕在class文件被轉(zhuǎn)化為dex文件之前去修改,在Transfrom這個(gè)api出來之前,想要在項(xiàng)目被打包成dex之前對(duì)class進(jìn)行操作,必須自定義一個(gè)Task,然后插入到predex或者dex之前,在自定義的Task中可以使用javassist或者asm對(duì)class進(jìn)行操作,而Transform則更為方便,Transfrom會(huì)有他自己的執(zhí)行時(shí)機(jī),不需要我們插入到某個(gè)Task前面。Tranfrom一經(jīng)注冊(cè)便會(huì)自動(dòng)添加到Task執(zhí)行序列中,并且正好是項(xiàng)目被打包成dex之前。
難點(diǎn):
相比ASM,Javassist對(duì)java極度友好的api更容易快速上手,難點(diǎn)在思想的應(yīng)用,小到切片邏輯的控制,如本例中的性能log打印日志,大到宏觀的熱修復(fù),插件化中對(duì)preDex的操作修改,劍客精神到了這一層級(jí),已經(jīng)是上帝視角,無所不能。
優(yōu)點(diǎn):
由于Javassist可以直接操作修改編譯后的字節(jié)碼,直接繞過了java編譯器,所以可以做很多突破限制的事情,例如,跨dex引用,解決熱修復(fù)中CLASS_ISPREVERIFIED的問題。
開源項(xiàng)目與鏈接學(xué)習(xí):
1、https://github.com/north2016/T-MVP(面向切面編程APT、AspectJ、Javassist項(xiàng)目實(shí)踐)
2、http://m.itdecent.cn/p/dca3e2c8608a(安卓AOP三劍客:APT、AspectJ、Javassist)
AOP的使用:
1、日志記錄:業(yè)務(wù)埋點(diǎn)
2、持久化
3、性能監(jiān)控:性能日志
4、數(shù)據(jù)校驗(yàn):方法的參數(shù)校驗(yàn)
5、緩存:內(nèi)存緩存和持久緩存
6、權(quán)限檢查:業(yè)務(wù)權(quán)限(如登陸,或用戶等級(jí))、系統(tǒng)權(quán)限(如拍照定位)
7、異常處理
總結(jié):
面向切面編程使得橫切關(guān)注點(diǎn)的實(shí)現(xiàn)與主要業(yè)務(wù)邏輯分離,提高了代碼的可維護(hù)性和可重用性,它可以減少代碼的重復(fù)性,將一些通用的功能集中在切面中實(shí)現(xiàn),使得代碼更加清晰、簡(jiǎn)潔,同時(shí),AOP還提供了更大的靈活性,可以在不修改原有代碼的情況下添加、刪除或修改橫切關(guān)注點(diǎn)的行為需要注意的是,AOP并不適用于所有場(chǎng)景,它主要用于解決橫切關(guān)注點(diǎn)的問題,在某些情況下,如果橫切關(guān)注點(diǎn)與主要業(yè)務(wù)邏輯高度耦合,使用AOP可能會(huì)導(dǎo)致代碼的可讀性和維護(hù)性下降,因此,在使用AOP時(shí)需要謹(jǐn)慎權(quán)衡,并根據(jù)具體場(chǎng)景選擇合適的編程范式和技術(shù)。
三:響應(yīng)式編程
響應(yīng)式編程(Reactive?Programming)是一種以數(shù)據(jù)流(Data?Stream)和自動(dòng)響應(yīng)(Automatic?Reaction)為核心的編程范式,旨在簡(jiǎn)化異步操作(如網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)庫(kù)讀寫、UI事件)和狀態(tài)變化(如數(shù)據(jù)更新、用戶輸入)的處理,最終實(shí)現(xiàn)數(shù)據(jù)驅(qū)動(dòng) UI的開發(fā)模式,它主要關(guān)注數(shù)據(jù)流的變化和處理,通過使用觀察者模式、函數(shù)式編程和流式操作等技術(shù),實(shí)現(xiàn)對(duì)數(shù)據(jù)流的監(jiān)聽、轉(zhuǎn)換和處理,在響應(yīng)式編程中,數(shù)據(jù)流被視為一系列連續(xù)變化的事件流,稱為"流"(Stream),這些流可以包含來自不同來源的數(shù)據(jù),編程者可以通過訂閱這些流,以響應(yīng)數(shù)據(jù)的變化和事件的發(fā)生。
一、核心定義:從“命令式”到“響應(yīng)式”的轉(zhuǎn)變
要理解響應(yīng)式編程,首先需要對(duì)比傳統(tǒng)的命令式編程:
命令式編程:開發(fā)者需手動(dòng)編寫“步驟化指令”,明確告訴程序“先做什么、再做什么”,例如,發(fā)起網(wǎng)絡(luò)請(qǐng)求后,需在回調(diào)中手動(dòng)更新UI,監(jiān)聽EditText輸入時(shí),需在TextWatcher中手動(dòng)處理文本變化。
響應(yīng)式編程:開發(fā)者只需定義“數(shù)據(jù)流的來源”和“數(shù)據(jù)變化時(shí)的響應(yīng)邏輯”,程序會(huì)自動(dòng)監(jiān)聽數(shù)據(jù)流的變化,并觸發(fā)對(duì)應(yīng)的響應(yīng),例如,定義“網(wǎng)絡(luò)數(shù)據(jù)?→?UI更新”的映射關(guān)系后,當(dāng)網(wǎng)絡(luò)數(shù)據(jù)返回時(shí),UI會(huì)自動(dòng)更新,無需手動(dòng)調(diào)用setText()。
二、響應(yīng)式編程的核心特性
響應(yīng)式編程的本質(zhì)是圍繞“數(shù)據(jù)流”展開,所有特性都服務(wù)于“高效處理數(shù)據(jù)流的產(chǎn)生、傳遞、變換和消費(fèi)”,以下是關(guān)鍵特性及Android中的對(duì)應(yīng)場(chǎng)景:
1、數(shù)據(jù)流(Data?Stream):一切皆可流
“數(shù)據(jù)流”是響應(yīng)式編程的核心載體,指按時(shí)間順序產(chǎn)生的一系列數(shù)據(jù)事件,在Android中,幾乎所有異步/狀態(tài)變化都可以抽象為數(shù)據(jù)流:
用戶交互流:按鈕點(diǎn)擊、EditText輸入、RecyclerView滑動(dòng)。
數(shù)據(jù)流:網(wǎng)絡(luò)請(qǐng)求返回的JSON、Room數(shù)據(jù)庫(kù)的查詢結(jié)果、SharedPreferences的值變化。
系統(tǒng)事件流:Activity生命周期、網(wǎng)絡(luò)狀態(tài)變化、電量低提醒。
這些數(shù)據(jù)流可以被“觀察”(Observable),當(dāng)數(shù)據(jù)產(chǎn)生時(shí),會(huì)自動(dòng)通知“觀察者”(Observer)執(zhí)行邏輯。
2、異步處理:告別“回調(diào)地獄”
Android中異步操作(如網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)庫(kù)讀寫)傳統(tǒng)上依賴回調(diào)(Callback),當(dāng)多個(gè)異步操作嵌套時(shí)(例如:先請(qǐng)求Token → 再用Token請(qǐng)求用戶信息 → 最后緩存到本地),會(huì)產(chǎn)生“回調(diào)地獄”(Callback?Hell),代碼可讀性和可維護(hù)性極差:
//?傳統(tǒng)回調(diào)地獄示例
requestToken(new?TokenCallback()?{
????@Override
????public?void?onSuccess(String?token)?{
????????requestUserInfo(token,?new?UserCallback()?{
????????????@Override
????????????public?void?onSuccess(User?user)?{
????????????????saveUserToLocal(user,?new?SaveCallback()?{
????????????????????@Override
????????????????????public?void?onSuccess()?{
????????????????????????//?最終更新UI
????????????????????}
????????????????????@Override
????????????????????public?void?onFailure(Exception?e)?{}
????????????????});
????????????}
????????????@Override
????????????public?void?onFailure(Exception?e)?{}
????????});
????}
????@Override
????public?void?onFailure(Exception?e)?{}
});
響應(yīng)式編程通過“數(shù)據(jù)流鏈?zhǔn)秸{(diào)用”解決回調(diào)地獄,將多個(gè)異步操作串聯(lián)為“流的變換管道”,代碼線性且清晰:
//?RxJava?示例(響應(yīng)式框架)
requestTokenStream()? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//?流1:請(qǐng)求Token
????.flatMap?{?token?->?requestUserInfoStream(token)?}? ? ? //?流2:用Token請(qǐng)求用戶信息(變換流)
????.flatMap?{?user?->?saveUserToLocalStream(user)?}? ? ? ? ? //?流3:緩存用戶(變換流)
????.observeOn(AndroidSchedulers.mainThread())?//?指定UI線程響應(yīng)
????.subscribe(
????????{?//?數(shù)據(jù)成功:更新UI
????????????tvUserName.text?=?it.name
????????},
????????{?e?->?//?錯(cuò)誤:提示用戶
????????????Toast.makeText(context,?"請(qǐng)求失敗",?Toast.LENGTH_SHORT).show()
????????}
????)
3、自動(dòng)響應(yīng):數(shù)據(jù)變化,UI/邏輯自動(dòng)變化
響應(yīng)式編程的核心目標(biāo)是“數(shù)據(jù)驅(qū)動(dòng)”:當(dāng)數(shù)據(jù)源(如網(wǎng)絡(luò)數(shù)據(jù)、數(shù)據(jù)庫(kù))發(fā)生變化時(shí),依賴該數(shù)據(jù)的邏輯(如UI更新、業(yè)務(wù)計(jì)算)會(huì)自動(dòng)觸發(fā),無需手動(dòng)調(diào)用更新方法。
例如,使用Kotlin?Flow(Jetpack原生響應(yīng)式API)觀察Room數(shù)據(jù)庫(kù)數(shù)據(jù):
//?1、Room數(shù)據(jù)庫(kù)定義:返回Flow(數(shù)據(jù)流),數(shù)據(jù)變化時(shí)自動(dòng)發(fā)射新值
@Query("SELECT?*?FROM?user?WHERE?id?=?:userId")
fun?getUserById(userId:?String):?Flow<User>
//?2、ViewModel中觀察數(shù)據(jù)流
val?userFlow?=?userDao.getUserById("123")
//?3、Activity中收集數(shù)據(jù)流:數(shù)據(jù)變化時(shí)自動(dòng)更新UI
lifecycleScope.launch?{
????viewModel.userFlow
????????.flowOn(Dispatchers.IO)?//?指定數(shù)據(jù)庫(kù)查詢?cè)贗O線程
????????.collect?{?user?->?
????????????//?自動(dòng)響應(yīng):數(shù)據(jù)變化時(shí)更新UI
????????????tvUserName.text?=?user.name
????????????tvUserAge.text?=?user.age.toString()
????????}
}
當(dāng)數(shù)據(jù)庫(kù)中id=123的用戶數(shù)據(jù)被修改時(shí),collect塊會(huì)自動(dòng)執(zhí)行,UI隨之更新,無需手動(dòng)查詢數(shù)據(jù)庫(kù)并調(diào)用setText()。
4、背壓(Backpressure):解決“生產(chǎn)者速度?>?消費(fèi)者速度”
在響應(yīng)式編程中,生產(chǎn)者(如快速產(chǎn)生數(shù)據(jù)的傳感器、高頻網(wǎng)絡(luò)推送)可能比消費(fèi)者(如UI更新、數(shù)據(jù)處理)速度快,導(dǎo)致數(shù)據(jù)堆積、內(nèi)存溢出(OOM),背壓就是解決這一問題的機(jī)制:讓消費(fèi)者告訴生產(chǎn)者我能處理多少數(shù)據(jù),請(qǐng)放慢速度。
例如,Android中監(jiān)聽設(shè)備傳感器(如加速度傳感器)時(shí),傳感器每秒產(chǎn)生數(shù)十條數(shù)據(jù),但UI每秒只能更新60次,此時(shí)通過背壓策略(如“丟棄多余數(shù)據(jù)”“緩沖固定數(shù)量”)控制數(shù)據(jù)流速:
//?RxJava背壓示例:使用Buffer策略緩沖數(shù)據(jù),避免溢出
Observable.interval(10,?TimeUnit.MILLISECONDS)? ?//?生產(chǎn)者:每10ms產(chǎn)生1個(gè)數(shù)據(jù)(每秒100個(gè))
????.onBackpressureBuffer(20)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //?背壓策略:緩沖20個(gè)數(shù)據(jù),超出則丟棄
????.observeOn(AndroidSchedulers.mainThread())
????.subscribe?{?data?->
????????//?消費(fèi)者:UI更新(每秒最多60次)
????????tvSensorData.text?=?data.toString()
????}
三、Android中常用的響應(yīng)式框架/API
Android生態(tài)中,響應(yīng)式編程主要通過以下工具實(shí)現(xiàn),各有適用場(chǎng)景:

四、總結(jié)
優(yōu)勢(shì):
1、簡(jiǎn)化異步代碼:消除回調(diào)地獄,代碼線性化、可讀性高。
2、數(shù)據(jù)驅(qū)動(dòng)?UI:數(shù)據(jù)變化自動(dòng)觸發(fā)UI更新,減少手動(dòng)同步邏輯。
3、生命周期安全:主流框架(如RxAndroid、LiveData)支持生命周期綁定,避免Activity銷毀后更新UI導(dǎo)致的崩潰。
4、豐富的操作符:如過濾(filter)、映射(map)、合并(merge),快速處理數(shù)據(jù)流。
注意事項(xiàng):
1、學(xué)習(xí)曲線較陡:需理解“流”“觀察者”“操作符”等概念,初期上手慢。
2、避免過度使用:簡(jiǎn)單場(chǎng)景(如單次網(wǎng)絡(luò)請(qǐng)求)用協(xié)程+回調(diào)即可,無需強(qiáng)行用響應(yīng)式。
3、內(nèi)存泄漏風(fēng)險(xiǎn):若忘記取消訂閱(如RxJava的Disposable、Flow的cancel),會(huì)導(dǎo)致內(nèi)存泄漏。
4、調(diào)試難度高:異步流的執(zhí)行順序較難追蹤,需借助專門工具(如RxJava的RxDebugger)。
響應(yīng)式編程的核心是“以數(shù)據(jù)流為中心,讓程序自動(dòng)響應(yīng)數(shù)據(jù)變化”,在Android開發(fā)中,它尤其適合處理復(fù)雜的異步場(chǎng)景(如網(wǎng)絡(luò)+數(shù)據(jù)庫(kù)+UI聯(lián)動(dòng)),通過主流框架(如Kotlin?Flow、RxJava)可以大幅提升代碼的可維護(hù)性和穩(wěn)定性,對(duì)于新手,建議從簡(jiǎn)單場(chǎng)景(如用LiveData更新UI)入手,逐步過渡到復(fù)雜流處理。
四:函數(shù)式編程
函數(shù)式編程(functional?programming)或稱函數(shù)程序設(shè)計(jì)、泛函編程,是一種編程范式,它將電腦運(yùn)算視為函數(shù)運(yùn)算,并且避免使用程序狀態(tài)以及易變對(duì)象,其中,λ?演算(lambda?calculus)為該語言最重要的基礎(chǔ),而且,λ?演算的函數(shù)可以接受函數(shù)當(dāng)作輸入(引數(shù))和輸出(傳出值),比起指令式編程,函數(shù)式編程更加強(qiáng)調(diào)程序執(zhí)行的結(jié)果而非執(zhí)行的過程,倡導(dǎo)利用若干簡(jiǎn)單的執(zhí)行單元讓計(jì)算結(jié)果不斷漸進(jìn),逐層推導(dǎo)復(fù)雜的運(yùn)算,而不是設(shè)計(jì)一個(gè)復(fù)雜的執(zhí)行過程。
Kotlin作為一門多范式編程語言,對(duì)函數(shù)式編程(Functional?Programming,?FP)提供了原生且全面的支持,它并非純函數(shù)式語言(如Haskell),但通過設(shè)計(jì)理念和語法特性,將函數(shù)式思想與面向?qū)ο?、命令式等范式無縫融合,讓開發(fā)者可以靈活運(yùn)用函數(shù)式風(fēng)格解決問題。
Kotlin如何支持函數(shù)式編程:
函數(shù)式編程的核心思想(如“函數(shù)是一等公民”、不可變數(shù)據(jù)、純函數(shù)、函數(shù)組合等),在Kotlin中通過以下特性得到直接體現(xiàn):
1、函數(shù)是“一等公民”
在函數(shù)式編程中,函數(shù)可以像變量一樣被傳遞、賦值、作為參數(shù)或返回值,這是函數(shù)式的基石,Kotlin對(duì)此提供了完整支持:
函數(shù)類型:可直接聲明函數(shù)類型(如 (Int,?Int)?->?Int表示接收兩個(gè)Int并返回Int的函數(shù))。
函數(shù)引用:通過::符號(hào)將函數(shù)轉(zhuǎn)換為對(duì)象(如::add引用add函數(shù))。
高階函數(shù):接收函數(shù)作為參數(shù)或返回函數(shù)的函數(shù)(如map、filter)。
代碼示例:
//?定義一個(gè)函數(shù)
fun?add(a:?Int,?b:?Int):?Int?=?a?+?b
//?函數(shù)作為參數(shù)(高階函數(shù))
fun?calculate(a:?Int,?b:?Int,?operation:?(Int,?Int)?->?Int):?Int?{
????return?operation(a,?b)?//?調(diào)用傳入的函數(shù)
}
fun?main()?{
????//?傳遞函數(shù)引用作為參數(shù)
????val?result?=?calculate(2,?3,?::add)?
????println(result)?//?輸出:5
}
2、不可變數(shù)據(jù)與純函數(shù)
函數(shù)式編程強(qiáng)調(diào)不可變數(shù)據(jù)(避免狀態(tài)修改帶來的副作用)和純函數(shù)(輸入決定輸出,無副作用),Kotlin為此提供了直接支持:
不可變變量:用val聲明不可變變量(初始化后無法修改),默認(rèn)推薦優(yōu)先使用。
不可變集合:標(biāo)準(zhǔn)庫(kù)提供List、Set、Map等不可變集合(如listOf()創(chuàng)建的集合無法修改)。
純函數(shù)友好:語法設(shè)計(jì)鼓勵(lì)無副作用的函數(shù)(如無var修改、無IO操作的函數(shù))。
代碼示例:
//?純函數(shù):輸入相同則輸出必相同,無副作用
fun?multiply(a:?Int,?b:?Int):?Int?=?a?*?b? ? //?僅依賴輸入,不修改外部狀態(tài)
fun?main()?{
????val?numbers?=?listOf(1,?2,?3)? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//?不可變集合(無法add/remove元素)
????val?doubled?=?numbers.map?{?multiply(it,?2)?}?//?純函數(shù)組合
????println(doubled)?//?輸出:[2,?4,?6]
}
3、Lambda表達(dá)式與匿名函數(shù)
函數(shù)式編程中,“匿名函數(shù)”(無需命名的臨時(shí)函數(shù))是簡(jiǎn)化代碼的重要工具,Kotlin通過lambda表達(dá)式原生支持這一特性,讓函數(shù)式操作(如集合處理)更簡(jiǎn)潔。
代碼示例:
fun?main()?{
????val?numbers?=?1..10
????//?用lambda實(shí)現(xiàn)過濾(函數(shù)式風(fēng)格)
????val?evenNumbers?=?numbers.filter?{?it?%?2?==?0?}?//?匿名函數(shù):篩選偶數(shù)
????//?用?lambda?實(shí)現(xiàn)映射
????val?squared?=?evenNumbers.map?{?it?*?it?}?//?匿名函數(shù):計(jì)算平方
????println(squared)?//?輸出:[4,?16,?36,?64,?100]
}
4、函數(shù)組合與管道操作
函數(shù)式編程的核心能力之一是將多個(gè)簡(jiǎn)單函數(shù)組合為復(fù)雜邏輯(類似“管道”:數(shù)據(jù)經(jīng)過多個(gè)函數(shù)處理,每個(gè)函數(shù)輸出作為下一個(gè)的輸入),Kotlin標(biāo)準(zhǔn)庫(kù)提供了豐富的高階函數(shù)支持這種組合:
map:轉(zhuǎn)換元素;
filter:篩選元素;
reduce/fold:聚合元素;
flatMap:展平嵌套集合;
takeWhile:按條件取元素。
代碼示例:
data?class?Person(val?name:?String,?val?age:?Int)
fun?main()?{
????val?people?=?listOf(
????????Person("Alice",?23),
????????Person("Bob",?17),
????????Person("Charlie",?30),
????????Person("David",?25)
????)
????//?函數(shù)組合:篩選成年人?→?提取姓名?→?按字母排序
????val?adultNames?=?people
????????.filter?{?it.age?>=?18?}?//?篩選
????????.map?{?it.name?}?//?轉(zhuǎn)換
????????.sorted()?//?排序
????println(adultNames)?//?輸出:[Alice,?Charlie,?David]
}
5、序列(Sequences):惰性求值
函數(shù)式編程中,“惰性求值”(Lazy?Evaluation)可以避免不必要的中間計(jì)算,提升效率,Kotlin提供Sequence類型支持惰性操作:集合轉(zhuǎn)換時(shí),Sequence不會(huì)立即執(zhí)行,而是在終端操作(如toList())時(shí)才一次性計(jì)算,減少中間集合的創(chuàng)建。
代碼示例:
fun?main()?{
????//?普通List:每一步操作都創(chuàng)建新集合(eager求值)
????val?listResult?=?(1..100).toList()
????????.filter?{?it?%?2?==?0?}
????????.map?{?it?*?2?}
????????.take(5)?//?仍會(huì)計(jì)算所有偶數(shù)的平方,再取前5個(gè)
????//?Sequence:惰性求值(僅計(jì)算必要的元素)
????val?sequenceResult?=?(1..100).asSequence()
????????.filter?{?it?%?2?==?0?}
????????.map?{?it?*?2?}
????????.take(5)?//?只計(jì)算前5個(gè)偶數(shù)的平方,效率更高
????????.toList()
????println(sequenceResult)?//?輸出:[4,?8,?12,?16,?20]
}
6、無副作用的流處理:Flow
在異步場(chǎng)景中,函數(shù)式編程的“數(shù)據(jù)流”思想可通過Kotlin的Flow實(shí)現(xiàn),F(xiàn)low是基于協(xié)程的響應(yīng)式流,支持無副作用的異步數(shù)據(jù)處理,符合函數(shù)式中“數(shù)據(jù)流即函數(shù)組合”的理念。
代碼示例:
//?函數(shù)式風(fēng)格的數(shù)據(jù)流:無副作用,純轉(zhuǎn)換
fun?main()?=?runBlocking?{
????//?定義數(shù)據(jù)流(發(fā)射1,2,3)
????val?numbers?=?flow?{
????????for?(i?in?1..3)?{
????????????delay(100)?//?模擬異步操作
????????????emit(i)
????????}
????}
????//?流處理:函數(shù)組合(過濾→轉(zhuǎn)換)
????numbers
????????.filter?{?it?%?2?==?1?}?//?保留奇數(shù)
????????.map?{?it?*?10?}?//?乘以10
????????.collect?{?println(it)?}?//?終端操作:輸出
}
//?輸出:
//?10(100ms后)
//?30(再200ms后)
總結(jié):
Kotlin并非強(qiáng)制使用函數(shù)式編程,而是將函數(shù)式思想作為核心能力之一,與其他范式(如面向?qū)ο螅o縫融合,支持函數(shù)式的核心特性(一等函數(shù)、不可變數(shù)據(jù)、純函數(shù)、函數(shù)組合等),提供簡(jiǎn)潔語法(lambda、高階函數(shù))降低函數(shù)式編程的使用成本,允許開發(fā)者根據(jù)場(chǎng)景靈活選擇:簡(jiǎn)單邏輯用命令式,復(fù)雜轉(zhuǎn)換用函數(shù)式,異步流用Flow等。
特點(diǎn):
純函數(shù):函數(shù)式編程強(qiáng)調(diào)使用純函數(shù),即沒有副作用、只依賴于輸入?yún)?shù)并返回結(jié)果的函數(shù)。
不可變數(shù)據(jù):函數(shù)式編程鼓勵(lì)使用不可變數(shù)據(jù),避免修改已有數(shù)據(jù),而是通過創(chuàng)建新的數(shù)據(jù)來實(shí)現(xiàn)狀態(tài)的改變。
函數(shù)組合:函數(shù)式編程支持函數(shù)的組合,可以將多個(gè)函數(shù)組合成一個(gè)更復(fù)雜的函數(shù),提高代碼的復(fù)用性和可讀性。
延遲計(jì)算:函數(shù)式編程中的操作通常是延遲計(jì)算的,只有在需要結(jié)果時(shí)才會(huì)進(jìn)行計(jì)算,這提供了更高的靈活性和效率。
優(yōu)點(diǎn):
可讀性:函數(shù)式編程強(qiáng)調(diào)代碼的表達(dá)能力和可讀性,使代碼更易于理解和維護(hù)。
可測(cè)試性:純函數(shù)和不可變數(shù)據(jù)使函數(shù)式代碼更易于測(cè)試,減少了對(duì)外部狀態(tài)和依賴的需求。
并發(fā)性:函數(shù)式編程天然適合并發(fā)編程,由于純函數(shù)沒有副作用,可以安全地在多線程環(huán)境中執(zhí)行。
挑戰(zhàn)和限制:
學(xué)習(xí)曲線:函數(shù)式編程的概念和技巧需要一定的學(xué)習(xí)和適應(yīng)時(shí)間。
性能問題:某些情況下,函數(shù)式編程可能導(dǎo)致額外的內(nèi)存和計(jì)算開銷,需要權(quán)衡性能和代碼簡(jiǎn)潔性之間的關(guān)系。
生態(tài)系統(tǒng):與面向?qū)ο缶幊滔啾?,函?shù)式編程在某些編程語言和框架中的支持和生態(tài)系統(tǒng)可能相對(duì)較少。
總的來說,函數(shù)式編程是一種強(qiáng)調(diào)函數(shù)和數(shù)據(jù)的不變性、組合和延遲計(jì)算的編程范式,它能夠提供可讀性強(qiáng)、可測(cè)試性高和并發(fā)性好等優(yōu)點(diǎn),然而,選擇使用函數(shù)式編程還是傳統(tǒng)的命令式編程取決于具體的應(yīng)用場(chǎng)景和需求。
五:命令式編程
命令式編程是一種以指令的形式描述計(jì)算機(jī)執(zhí)行的具體步驟的編程范式,在命令式編程中,開發(fā)人員需要逐步指定計(jì)算機(jī)執(zhí)行的操作,包括數(shù)據(jù)的獲取、處理和存儲(chǔ)等,這種編程范式關(guān)注計(jì)算機(jī)的狀態(tài)變化和控制流程,通過改變狀態(tài)和控制流程來實(shí)現(xiàn)所需的計(jì)算目標(biāo)。
命令式編程的特點(diǎn):
public?class?CommandExample?{
????public?static?void?main(String[]?args)?{
????????int?num1?=?5;
????????int?num2?=?10;
????????int?sum?=?0;
????????//?計(jì)算兩個(gè)數(shù)的和
????????sum?=?num1?+?num2;
????????//?打印結(jié)果
????????System.out.println("Sum:?"?+?sum);
????}
}
在上面的示例中,我們通過逐步指定計(jì)算機(jī)執(zhí)行的操作來實(shí)現(xiàn)兩個(gè)數(shù)的相加,并將結(jié)果打印出來,即通過一系列的命令來改變計(jì)算機(jī)的狀態(tài)(變量的賦值)和控制流程(指令的順序執(zhí)行),開發(fā)人員需要顯式地指定每個(gè)操作的細(xì)節(jié),以實(shí)現(xiàn)所需的計(jì)算邏輯。
總結(jié):
優(yōu)點(diǎn):
直觀性:命令式代碼往往更容易理解和調(diào)試,因?yàn)椴僮骱蛨?zhí)行順序直接可見。
靈活性:命令式編程允許開發(fā)人員精確控制計(jì)算機(jī)的狀態(tài)和行為,適用于各種復(fù)雜的計(jì)算任務(wù)。
缺點(diǎn):
復(fù)雜性:隨著程序規(guī)模的增長(zhǎng),命令式代碼可能變得冗長(zhǎng)、復(fù)雜,難以維護(hù)和擴(kuò)展。
可變性:命令式編程通常涉及可變狀態(tài),可能導(dǎo)致并發(fā)和并行執(zhí)行的困難以及不確定性的問題。
總體而言,命令式編程是一種常見且實(shí)用的編程范式,特別適用于需要精確控制計(jì)算機(jī)行為和狀態(tài)的情況。
六:聲明式編程
聲明式編程(Declarative?Programming)是一種關(guān)注描述問題邏輯和規(guī)則編程范式,而不是指定如何執(zhí)行解決問題的步驟,在聲明式編程中,我們通過聲明所需的結(jié)果和約束條件,讓計(jì)算機(jī)自行推導(dǎo)出解決方案,而不需要明確指定每個(gè)步驟的執(zhí)行細(xì)節(jié)。
在Android開發(fā)中,聲明式編程是一種以?“描述目標(biāo)結(jié)果”?為核心的開發(fā)范式,與傳統(tǒng)的?“命令式編程”?形成鮮明對(duì)比,它的核心思想是:開發(fā)者只需聲明?“UI?應(yīng)該是什么樣的”(基于當(dāng)前狀態(tài)),而無需手動(dòng)編寫?“如何從當(dāng)前狀態(tài)更新到目標(biāo)狀態(tài)”?的步驟(如手動(dòng)調(diào)用setText、setVisibility等),在Android場(chǎng)景下,聲明式編程主要體現(xiàn)在UI開發(fā)和狀態(tài)管理中,核心是:
1、關(guān)注?“是什么”?而非?“怎么做”:例如,“當(dāng)用戶點(diǎn)擊按鈕時(shí),文本顯示‘已點(diǎn)擊’”,而非?“監(jiān)聽按鈕點(diǎn)擊事件?→?獲取文本控件?→?調(diào)用setText("已點(diǎn)擊")”。
2、狀態(tài)驅(qū)動(dòng)UI:UI是狀態(tài)的“映射”(UI?=?f(State)),當(dāng)狀態(tài)變化時(shí),框架自動(dòng)更新UI,無需手動(dòng)操作視圖。
Android傳統(tǒng)開發(fā)(基于XML+View體系)屬于命令式編程,而現(xiàn)代的Jetpack?Compose則是聲明式編程的典型實(shí)現(xiàn),兩者的核心差異如下:

Android?聲明式編程的典型實(shí)現(xiàn):Jetpack?Compose
Jetpack?Compose是Google推出的聲明式UI框架,是Android聲明式編程的核心載體,它通過以下特性實(shí)現(xiàn)聲明式思想:
以?“函數(shù)”?描述?UI(Composable函數(shù))
在Compose中,UI通過Composable?函數(shù)聲明:這些函數(shù)直接描述“當(dāng)前狀態(tài)下UI應(yīng)該是什么樣”,而非步驟。
//?聲明式UI:直接描述“一個(gè)顯示用戶名的文本”
@Composable
fun?Greeting(name:?String)?{
????//?僅聲明“文本內(nèi)容是name,字體大小24sp”
????Text(
????????text?=?"Hello,?$name!",
????????fontSize?=?24.sp
????)
}
狀態(tài)驅(qū)動(dòng)UI更新:
Compose的核心是“狀態(tài)驅(qū)動(dòng)”:當(dāng)狀態(tài)變化時(shí),框架自動(dòng)重新執(zhí)行依賴該狀態(tài)的Composable函數(shù),實(shí)現(xiàn)UI更新,開發(fā)者無需手動(dòng)調(diào)用任何更新方法。
@Composable
fun?Counter()?{
????//?聲明狀態(tài):count(用remember保持狀態(tài),mutableStateOf使?fàn)顟B(tài)可觀察)
????var?count?by?remember?{?mutableStateOf(0)?}
????//?聲明UI:基于當(dāng)前count狀態(tài)
????Column(
????????modifier?=?Modifier.fillMaxSize(),
????????horizontalAlignment?=?Alignment.CenterHorizontally,
????????verticalArrangement?=?Arrangement.Center
????)?{
????????//?文本顯示當(dāng)前count(狀態(tài)映射)
????????Text(text?=?"當(dāng)前計(jì)數(shù):$count",?fontSize?=?24.sp)
????????//?按鈕點(diǎn)擊時(shí)修改狀態(tài)(僅關(guān)注“狀態(tài)變化”,不關(guān)心UI如何更新)
????????Button(onClick?=?{?count++?})?{
????????????Text("點(diǎn)擊加1")
????????}
????}
}
@Preview
@Composable
fun?CounterPreview()?{
????Counter()
}
核心邏輯:
當(dāng)用戶點(diǎn)擊按鈕,count狀態(tài)自增(僅修改狀態(tài)),框架自動(dòng)檢測(cè)到count變化,重新執(zhí)行Counter函數(shù),新的count值被傳入Text,UI自動(dòng)更新,無需手動(dòng)調(diào)用setText。
聲明式編程的優(yōu)勢(shì):
代碼簡(jiǎn)潔:消除了命令式編程中的模板代碼(如findViewById、setOnClickListener、notifyDataSetChanged等),邏輯更集中。
狀態(tài)與UI解耦:UI完全由狀態(tài)驅(qū)動(dòng),避免了“忘記更新UI”或“更新邏輯錯(cuò)誤”導(dǎo)致的Bug。
易于維護(hù):UI描述與狀態(tài)邏輯在同一處,開發(fā)者無需在XML和代碼間來回切換。
天然支持預(yù)覽:Composable函數(shù)可通過@Preview注解實(shí)時(shí)預(yù)覽,提升開發(fā)效率。
總結(jié):
Android聲明式編程(以Jetpack?Compose為核心)通過“狀態(tài)驅(qū)動(dòng)UI”和“聲明式描述”,徹底改變了傳統(tǒng)命令式UI開發(fā)的模式,它讓開發(fā)者從“手動(dòng)操作視圖”中解放出來,更專注于“UI?應(yīng)該是什么樣”,而非“如何實(shí)現(xiàn)更新”,最終提升開發(fā)效率和代碼可維護(hù)性,隨著Jetpack?Compose成為Android官方推薦的UI框架,聲明式編程已成為現(xiàn)代Android開發(fā)的主流范式。
優(yōu)點(diǎn):
簡(jiǎn)潔性:聲明式代碼通常更為簡(jiǎn)潔,不需要編寫大量的實(shí)現(xiàn)細(xì)節(jié),減少了冗余代碼和錯(cuò)誤的可能性。
可維護(hù)性:由于隱藏了底層實(shí)現(xiàn)細(xì)節(jié),聲明式代碼更易于維護(hù)和修改,提高了代碼的可維護(hù)性。
可擴(kuò)展性:聲明式代碼通常具有更好的可擴(kuò)展性,可以通過添加更多的聲明來處理更復(fù)雜的問題。
限制和挑戰(zhàn):
學(xué)習(xí)曲線:對(duì)于習(xí)慣于命令式編程的開發(fā)者來說,理解和掌握聲明式編程的概念和技巧可能需要一定的學(xué)習(xí)和適應(yīng)時(shí)間。
靈活性:在某些情況下,聲明式編程的靈活性可能受到限制,特定的問題可能需要更多的控制和定制。
總的來說,聲明式編程是一種強(qiáng)調(diào)描述問題邏輯和規(guī)則,讓計(jì)算機(jī)自行推導(dǎo)解決方案。
七:通用編程(又叫:泛型編程)
通用編程是一種旨在增加代碼的可重用性、可讀性和類型安全性的編程范式,它通過在代碼中使用類型參數(shù)來實(shí)現(xiàn)通用性,使得可以編寫適用于多種數(shù)據(jù)類型的通用算法和數(shù)據(jù)結(jié)構(gòu),通過參數(shù)化類型編寫與具體類型無關(guān)的通用代碼,實(shí)現(xiàn)?“一套邏輯支持多種數(shù)據(jù)類型”,提升復(fù)用率。
關(guān)鍵特點(diǎn):
1、類型參數(shù)化(如<T>):將類型作為?“參數(shù)”?傳入。
2、編譯期類型安全:避免類型轉(zhuǎn)換錯(cuò)誤。
Kotlin泛型支持協(xié)變(out)、逆變(in)等特性。
//?通用函數(shù):支持任何可比較類型(T:?Comparable<T>)
fun?<T?:?Comparable<T>>?sortList(list:?List<T>):?List<T>?{
????return?list.sorted()??//?依賴T的compareTo方法
}
fun?main()?{
????val?ints?=?listOf(3,?1,?2)
????val?strings?=?listOf("c",?"a",?"b")
????println(sortList(ints))???//?輸出:[1,?2,?3]
????println(sortList(strings))??//?輸出:[a,?b,?c]
}
總結(jié):
優(yōu)點(diǎn):
代碼重用:泛型可以適用于多種數(shù)據(jù)類型,減少了代碼的重復(fù)編寫。
類型安全:泛型在編譯時(shí)會(huì)進(jìn)行類型檢查,提前發(fā)現(xiàn)類型錯(cuò)誤,減少運(yùn)行時(shí)錯(cuò)誤。
可讀性和可維護(hù)性:泛型代碼更加清晰和易于理解,提高了代碼的可讀性和可維護(hù)性。
但是需要注意通用編程并不適用于所有情況,有些特定需求可能需要使用原始類型或進(jìn)行類型轉(zhuǎn)換,此外,泛型的類型擦除機(jī)制也可能導(dǎo)致在運(yùn)行時(shí)丟失類型信息的問題,總之,通用編程是一種強(qiáng)大的工具,可以提高代碼的靈活性和可重用性,并提供類型安全的編程環(huán)境,它在許多現(xiàn)代編程語言中得到廣泛應(yīng)用,并成為開發(fā)中的重要概念之一。
八:并發(fā)編程
并發(fā)編程是一種用于處理多個(gè)任務(wù)或操作在同一時(shí)間段內(nèi)并發(fā)執(zhí)行情況的編程范式,在并發(fā)編程中,程序可以同時(shí)執(zhí)行多個(gè)任務(wù),并且這些任務(wù)可能相互交互、競(jìng)爭(zhēng)資源或者需要同步,通過任務(wù)調(diào)度(多線程、協(xié)程等)實(shí)現(xiàn)多個(gè)任務(wù)的協(xié)同執(zhí)行,解決單任務(wù)效率瓶頸,強(qiáng)調(diào)?“任務(wù)并行性”。
關(guān)鍵特點(diǎn):
1、任務(wù)間可能存在資源競(jìng)爭(zhēng)(需同步機(jī)制)。
2、核心是?“任務(wù)調(diào)度”?而非單任務(wù)邏輯。
Kotlin中常用協(xié)程(Coroutines)實(shí)現(xiàn)輕量級(jí)并發(fā)。
suspend?fun?download(url:?String)?{
????delay(1000)??//?模擬網(wǎng)絡(luò)請(qǐng)求延遲
????println("下載完成:$url")
}
fun?main()?=?runBlocking?{??//?協(xié)程作用域
????//?并發(fā)啟動(dòng)兩個(gè)下載任務(wù)
launch?{?download("https://a.com")?}
launch?{?download("https://b.com")?}
}
//?輸出(順序可能交替):
//?下載完成:https://a.com
//?下載完成:https://b.com
總結(jié):
特點(diǎn):
并行執(zhí)行:多個(gè)任務(wù)或操作可以在同一時(shí)間段內(nèi)并發(fā)執(zhí)行,充分利用系統(tǒng)的資源。
競(jìng)爭(zhēng)條件:并發(fā)執(zhí)行可能導(dǎo)致資源競(jìng)爭(zhēng)和沖突,需要合理處理共享資源的訪問。
同步和互斥:使用同步機(jī)制(如鎖、信號(hào)量、條件變量等)來控制并發(fā)執(zhí)行的順序和訪問權(quán)限。
并發(fā)安全性:確保并發(fā)執(zhí)行的正確性和一致性,避免數(shù)據(jù)競(jìng)爭(zhēng)和不確定的行為。
優(yōu)點(diǎn):
提高系統(tǒng)性能:通過并發(fā)執(zhí)行任務(wù),可以提高系統(tǒng)的處理能力和響應(yīng)速度。
增強(qiáng)用戶體驗(yàn):并發(fā)編程可以使應(yīng)用程序在處理并發(fā)請(qǐng)求時(shí)更加流暢和高效。
充分利用硬件資源:利用多核處理器和多線程技術(shù),最大程度地發(fā)揮硬件的性能。
挑戰(zhàn)和難點(diǎn):
線程安全問題:多線程環(huán)境下,需要注意共享資源的訪問安全,避免數(shù)據(jù)競(jìng)爭(zhēng)和并發(fā)錯(cuò)誤。
死鎖和活鎖:不正確的同步操作可能導(dǎo)致線程死鎖或活鎖,影響系統(tǒng)的可用性。
調(diào)度和性能問題:線程的調(diào)度和上下文切換會(huì)帶來一定的開銷,不當(dāng)?shù)牟l(fā)設(shè)計(jì)可能導(dǎo)致性能下降。
因此,在并發(fā)編程中,合理的并發(fā)控制和同步機(jī)制的設(shè)計(jì)非常重要,以確保正確性、避免競(jìng)爭(zhēng)條件,并提高系統(tǒng)的性能和可靠性。
九:事件驅(qū)動(dòng)編程
事件驅(qū)動(dòng)編程是一種以事件為核心控制程序執(zhí)行流程的編程范式,其執(zhí)行依賴于事件的發(fā)生與處理,該模式通過識(shí)別、監(jiān)聽和響應(yīng)事件構(gòu)建程序邏輯,具備響應(yīng)性高、可維護(hù)性強(qiáng)、高效資源利用和非阻塞特性,廣泛應(yīng)用于用戶界面、實(shí)時(shí)系統(tǒng)、網(wǎng)絡(luò)服務(wù)及嵌入式開發(fā)等領(lǐng)域,它的核心思想是系統(tǒng)中的各個(gè)組件之間通過事件的觸發(fā)和響應(yīng)進(jìn)行通信和交互,在事件驅(qū)動(dòng)編程中,系統(tǒng)中的各個(gè)組件被設(shè)計(jì)成事件的消費(fèi)者或生產(chǎn)者,它們通過發(fā)布和訂閱事件的方式進(jìn)行通信。
涉及核心概念:
事件(Event):事件是系統(tǒng)中發(fā)生的特定動(dòng)作或狀態(tài)變化的表示,它可以是用戶操作、傳感器輸入、網(wǎng)絡(luò)消息等,事件可以攜帶相關(guān)的數(shù)據(jù)。
事件生產(chǎn)者(Event?Producer):事件生產(chǎn)者是能夠產(chǎn)生事件并將其發(fā)布到系統(tǒng)中的組件,它負(fù)責(zé)檢測(cè)和響應(yīng)特定的條件,然后觸發(fā)相應(yīng)的事件。
事件消費(fèi)者(Event?Consumer):事件消費(fèi)者訂閱并接收事件,然后根據(jù)事件的類型和數(shù)據(jù)執(zhí)行相應(yīng)的操作或邏輯,它可以是系統(tǒng)中的其他組件、回調(diào)函數(shù)、觀察者等。
事件處理器(Event?Handler):事件處理器是與特定類型的事件相關(guān)聯(lián)的代碼塊或函數(shù),當(dāng)事件發(fā)生時(shí),相應(yīng)的事件處理器會(huì)被調(diào)用來處理事件。
典型應(yīng)用場(chǎng)景:
GUI開發(fā):如Android中按鈕點(diǎn)擊(setOnClickListener)、文本輸入(addTextChangedListener),Kotlin用lambda簡(jiǎn)化監(jiān)聽代碼:
//?Android中點(diǎn)擊事件的Kotlin實(shí)現(xiàn)(事件驅(qū)動(dòng))
button.setOnClickListener{
????Toast.makeText(context,"按鈕點(diǎn)擊",?Toast.LENGTH_SHORT).show()}
網(wǎng)絡(luò)編程:如OkHttp的請(qǐng)求回調(diào),Kotlin用lambda簡(jiǎn)化:
//?網(wǎng)絡(luò)請(qǐng)求事件的響應(yīng)
okHttpClient.newCall(request).enqueue(object:?Callback?{
? ? ? ? ? ?overridefunonResponse(call:?Call,?response:?Response){
? ? ? ? ? ? //?成功事件響應(yīng)
? ? ? ? ? ?}overridefunonFailure(call:?Call,?e:?IOException){
? ? ? ? ? ?//?失敗事件響應(yīng)}
})
狀態(tài)管理:如MVVM中,UI監(jiān)聽ViewModel的狀態(tài)變化事件(通過LiveData或Flow)。
總結(jié):
Kotlin對(duì)事件驅(qū)動(dòng)編程的支持體現(xiàn)了其?“簡(jiǎn)潔性”?和?“靈活性”:
1、簡(jiǎn)單場(chǎng)景:用函數(shù)類型?+?lambda快速實(shí)現(xiàn)事件監(jiān)聽,減少模板代碼。
? ? ?復(fù)雜場(chǎng)景:用接口管理多事件類型,或用協(xié)程?+?Flow處理異步事件流。
? ? ?與框架結(jié)合:天然適配Android、Kotlin/JS等平臺(tái)的事件模型,提升開發(fā)效率。
2、事件驅(qū)動(dòng)編程的核心是?“關(guān)注事件與響應(yīng)”,而Kotlin的特性讓這種關(guān)注變得更加直接和高效,可以使系統(tǒng)更加靈活、響應(yīng)快速,并且各個(gè)組件之間解耦,降低了組件之間的直接依賴關(guān)系,它適用于構(gòu)建交互式和響應(yīng)式的應(yīng)用程序,特別是圖形用戶界面(GUI)和網(wǎng)絡(luò)應(yīng)用程序等場(chǎng)景。
十:邏輯編程
邏輯編程(Logic?Programming)是一種基于邏輯推理和規(guī)則匹配的思想來描述問題和求解問題的編程范式,在邏輯編程中,我們定義一組邏輯規(guī)則和事實(shí),通過邏輯推理系統(tǒng)自動(dòng)推導(dǎo)出解決方案。
特點(diǎn):
邏輯推理:基于邏輯規(guī)則和事實(shí)進(jìn)行推理和求解,通過自動(dòng)匹配和推導(dǎo)得到結(jié)果。
規(guī)則驅(qū)動(dòng):根據(jù)事實(shí)和規(guī)則的定義,邏輯編程系統(tǒng)能夠自動(dòng)推導(dǎo)出問題的解決方案,無需手動(dòng)指定具體步驟。
無副作用:邏輯編程不涉及變量狀態(tài)的修改和副作用,每次計(jì)算都是基于規(guī)則和事實(shí)的邏輯推理。
優(yōu)點(diǎn):
聲明性:邏輯編程的代碼更接近于問題的邏輯描述,更易于理解和閱讀。
自動(dòng)化推理:通過邏輯推理系統(tǒng)自動(dòng)推導(dǎo)出解決方案,減少了手動(dòng)編寫執(zhí)行步驟的工作。
邏輯表達(dá)能力:邏輯編程可以處理復(fù)雜的邏輯關(guān)系和約束,能夠表達(dá)豐富的問題領(lǐng)域。
限制和挑戰(zhàn):
效率問題:邏輯編程系統(tǒng)可能面臨推理效率的挑戰(zhàn),特別是在處理大規(guī)模問題時(shí)。
學(xué)習(xí)曲線:對(duì)于習(xí)慣于命令式編程的開發(fā)者來說,掌握邏輯編程的概念和技巧可能需要一定的學(xué)習(xí)和適應(yīng)時(shí)間。
限制性問題:邏輯編程的應(yīng)用范圍可能受到一些限制,某些問題可能更適合其他編程范式來解決。
總的來說,邏輯編程是一種基于邏輯推理和規(guī)則匹配的編程范式,通過定義邏輯規(guī)則和事實(shí),利用邏輯推理系統(tǒng)自動(dòng)推導(dǎo)出解決方案。
五:Android編程范式總結(jié)
編程范式在Android開發(fā)中并非孤立存在,而是伴隨系統(tǒng)演進(jìn)、技術(shù)迭代形成的“多層協(xié)同體系”,從早期的基礎(chǔ)實(shí)現(xiàn)到現(xiàn)代的高效開發(fā),每種范式都精準(zhǔn)解決了不同階段的核心痛點(diǎn),最終共同支撐起復(fù)雜應(yīng)用的構(gòu)建邏輯。
先看命令式編程,它是Android開發(fā)的“起點(diǎn)基石”,在Android初期(Java主導(dǎo)、XML布局為主的階段),命令式是最直接的實(shí)現(xiàn)方式,開發(fā)者需要通過“一步一指令”的方式操作UI、處理邏輯,比如早期用findViewById獲取控件實(shí)例,再調(diào)用setText、setVisibility手動(dòng)更新UI狀態(tài),或者在onClick回調(diào)中寫“點(diǎn)擊后彈出Toast→跳轉(zhuǎn)頁面”的線性邏輯,這種范式的核心是“關(guān)注過程”,開發(fā)者必須明確每一步操作的執(zhí)行順序和細(xì)節(jié),但它的局限也很明顯,當(dāng)UI復(fù)雜度提升(比如列表項(xiàng)包含多種狀態(tài)、頁面有大量動(dòng)態(tài)交互),命令式代碼會(huì)變得冗長(zhǎng)且易錯(cuò)(比如漏更UI狀態(tài)、多線程下的UI操作沖突),這也為后續(xù)范式的演進(jìn)埋下了伏筆。
再看面向?qū)ο缶幊蹋∣OP),它是Android架構(gòu)的“骨架支柱”,Android系統(tǒng)本身的設(shè)計(jì)就深度依賴OOP思想,四大組件(Activity、Service等)都是類的抽象,自定義View需繼承View類并重寫生命周期方法,甚至底層的View體系、事件分發(fā)機(jī)制(dispatchTouchEvent等方法的重寫與多態(tài))都是OOP的典型應(yīng)用,OOP通過“封裝、繼承、多態(tài)”解決了命令式編程的“代碼組織問題”,比如用BaseActivity封裝通用邏輯(如沉浸式狀態(tài)欄、權(quán)限請(qǐng)求),子類只需繼承即可復(fù)用,用“接口”定義回調(diào)規(guī)范(如OnClickListener),讓UI交互與邏輯處理解耦,用“數(shù)據(jù)類”(早期Java的Bean,后來Kotlin的data?class)封裝數(shù)據(jù)結(jié)構(gòu),統(tǒng)一數(shù)據(jù)傳遞格式,可以說OOP讓Android開發(fā)從“零散的指令堆砌”變成了“結(jié)構(gòu)化的組件組裝”,支撐了早期中大型應(yīng)用的代碼可維護(hù)性。
隨著Kotlin成為官方首選語言,函數(shù)式編程逐漸成為“異步與數(shù)據(jù)流的核心工具”,它的價(jià)值集中在“簡(jiǎn)化復(fù)雜邏輯的表達(dá)”,尤其解決了Android開發(fā)中長(zhǎng)期存在的“異步回調(diào)地獄”和“數(shù)據(jù)流處理繁瑣”問題,比如用高階函數(shù) + Lambda簡(jiǎn)化事件監(jiān)聽:傳統(tǒng)Java需要寫匿名內(nèi)部類實(shí)現(xiàn)OnClickListener,而Kotlin用view.setOnClickListener?{?...?}一行代碼搞定,本質(zhì)是將“行為邏輯”作為參數(shù)傳遞,用Coroutines(協(xié)程) 替代AsyncTask、Handler:協(xié)程通過“掛起/恢復(fù)”機(jī)制,讓異步代碼寫起來像同步代碼(比如launch?{?val?data?=?api.fetchData();updateUI(data)?}),避免了嵌套回調(diào)的混亂,用Flow處理數(shù)據(jù)流:比如網(wǎng)絡(luò)請(qǐng)求+本地?cái)?shù)據(jù)庫(kù)緩存的場(chǎng)景,F(xiàn)low可通過combine、filter等操作符串聯(lián)“網(wǎng)絡(luò)數(shù)據(jù)流”和“本地緩存流”,自動(dòng)響應(yīng)數(shù)據(jù)變化,而無需手動(dòng)寫“請(qǐng)求成功后更新緩存→通知UI”的繁瑣邏輯,函數(shù)式的核心是“關(guān)注結(jié)果而非過程”:開發(fā)者只需定義“數(shù)據(jù)如何轉(zhuǎn)換”“事件如何響應(yīng)”,無需關(guān)心底層的線程切換、流的生命周期管理。
如今,聲明式編程已成為UI開發(fā)的“主流范式”,其代表是Jetpack?Compose,它徹底顛覆了傳統(tǒng)XML+命令式的UI開發(fā)模式,傳統(tǒng)方式中,開發(fā)者需要先在XML定義布局結(jié)構(gòu),再在代碼中通過命令式操作更新UI,而聲明式的核心是“描述UI應(yīng)該是什么樣,而非怎么更新”,比如用Compose開發(fā)一個(gè)“加載狀態(tài)按鈕”,只需根據(jù)isLoading狀態(tài)描述UI(if?(isLoading)?CircularProgressIndicator()?else?Button(onClick?=?loadData)?{?Text("加載")?}),當(dāng)isLoading變化時(shí),Compose會(huì)自動(dòng)對(duì)比新舊狀態(tài)并更新UI,無需手動(dòng)調(diào)用setVisibility,這種范式的優(yōu)勢(shì)在于“狀態(tài)與UI的強(qiáng)綁定”,UI本質(zhì)是“狀態(tài)的映射”,開發(fā)者只需維護(hù)核心狀態(tài)(如加載中、成功、失敗),無需關(guān)注UI更新的細(xì)節(jié),大幅減少了“狀態(tài)不一致”的bug,也讓復(fù)雜UI(如動(dòng)態(tài)列表、多狀態(tài)切換頁面)的開發(fā)效率提升數(shù)倍。
最后,事件驅(qū)動(dòng)編程是貫穿始終的“邏輯串聯(lián)線”,Android應(yīng)用的本質(zhì)是“響應(yīng)事件的系統(tǒng)”,用戶點(diǎn)擊、手勢(shì)滑動(dòng)、網(wǎng)絡(luò)回調(diào)、生命周期變化(如onResume)、數(shù)據(jù)更新等都是“事件”,而應(yīng)用的運(yùn)行邏輯就是“事件觸發(fā)→狀態(tài)變化→UI響應(yīng)”的循環(huán)。早期事件驅(qū)動(dòng)依賴回調(diào)(如onClick、BroadcastReceiver),現(xiàn)代則結(jié)合函數(shù)式進(jìn)一步優(yōu)化:比如用Flow將“用戶輸入事件”“網(wǎng)絡(luò)事件”包裝成可觀察的“事件流”,通過collect監(jiān)聽并觸發(fā)狀態(tài)更新,在Compose中,用LaunchedEffect監(jiān)聽狀態(tài)變化事件,執(zhí)行異步操作(如狀態(tài)變?yōu)椤俺晒Α睍r(shí)彈出提示),事件驅(qū)動(dòng)讓應(yīng)用邏輯更“被動(dòng)且精準(zhǔn)”:只有當(dāng)事件發(fā)生時(shí)才執(zhí)行對(duì)應(yīng)邏輯,避免了無意義的輪詢或冗余計(jì)算。
這些范式并非“替代關(guān)系”,而是在現(xiàn)代Android開發(fā)中深度協(xié)同:比如用OOP的data?class定義數(shù)據(jù)模型(如User類封裝用戶信息),用函數(shù)式的Flow從網(wǎng)絡(luò)/本地?cái)?shù)據(jù)庫(kù)獲取并處理數(shù)據(jù)(userFlow.filter?{?it.isActive?}),用聲明式的Compose將數(shù)據(jù)狀態(tài)映射為UI(UserCard(user)),用事件驅(qū)動(dòng)串聯(lián)整個(gè)流程(用戶點(diǎn)擊“刷新”按鈕→觸發(fā)loadUser事件→Flow發(fā)射新數(shù)據(jù)→狀態(tài)更新→Compose自動(dòng)重組UI),這種“OOP做結(jié)構(gòu)、函數(shù)式處理流、聲明式畫UI、事件驅(qū)動(dòng)串邏輯”的協(xié)同模式,既保留了各范式的優(yōu)勢(shì),又解決了復(fù)雜應(yīng)用的開發(fā)效率和可維護(hù)性問題。
綜上,編程范式之于Android,是“技術(shù)演進(jìn)的縮影”,從命令式的基礎(chǔ)實(shí)現(xiàn),到OOP的架構(gòu)支撐,再到函數(shù)式的效率優(yōu)化、聲明式的UI革新,最終形成多范式協(xié)同的現(xiàn)代開發(fā)體系,它不僅改變了代碼的寫法,更重塑了開發(fā)者思考問題的方式:從“關(guān)注每一步操作”轉(zhuǎn)向“關(guān)注狀態(tài)與邏輯的映射”,讓Android開發(fā)從“繁瑣的細(xì)節(jié)堆砌”走向“高效的抽象設(shè)計(jì)”。