一纯露、面向?qū)ο笫鞘裁?/h4>
面向?qū)ο? (Object Oriented,OO) 的思想對軟件開發(fā)相當重要,它的概念和應(yīng)用甚至已超越了程序設(shè)計和軟件開發(fā),擴展到如數(shù)據(jù)庫系統(tǒng)、交互式界面瓶摆、應(yīng)用結(jié)構(gòu)、應(yīng)用平臺性宏、分布式系統(tǒng)群井、網(wǎng)絡(luò)管理結(jié)構(gòu)、CAD 技術(shù)毫胜、人工智能等領(lǐng)域书斜。面向?qū)ο笫且环N 對現(xiàn)實世界理解和抽象的方法,是計算機編程技術(shù)發(fā)展到一定階段后的產(chǎn)物指蚁。
面向過程 (Procedure Oriented) 是一種 以過程為中心 的編程思想菩佑。這些都是以什么正在發(fā)生為主要目標進行編程,不同于面向?qū)ο蟮氖钦l在受影響凝化。與面向?qū)ο竺黠@的不同就是 封裝稍坯、繼承、類搓劫。無論是在軟件開發(fā)還是在實際工作中瞧哟,深入地理解軟件開發(fā)的思想都非常有必要。
二枪向、從一場比賽說起
在一個軟件村里勤揩,有一名資深「面向過程」程序人員(老過)和一名「面向?qū)ο蟆剐磐剑òΓ┩瑫r受雇于一家挨踢店有一天老板突發(fā)奇想決定讓這兩名程序員進行一次比賽獲勝者將獲得一個限量的 360 度全自動按摩椅編程比賽開始了:
不一會,他倆都寫出了幾乎相同的代碼
class Bill{
// 獲取總價
fun getPrice(): Double {
val unit = getUnit()
val number = getNumber()
val price = unit * number
return price
}
// 獲取單價
fun getUnit(): Double {
...
}
// 獲取數(shù)量
fun getNumber(): Int {
...
}
}
老過看到新需求秘蛔,微微一笑
class Bill{
fun getPrice(): Double {
val unit = getUnit()
val number = getNumber()
val price = unit * number
if (todayIsLoversDay()) {
return price * 0.77
}
return price
}
fun getUnit(): Double {
...
}
fun getNumber(): Int {
...
}
fun todayIsLoversDay(): Boolean {
...
}
}
他決定讓新的收銀方式繼承 Bill 類
先在 Bill 類中新增 discount 方法
并將其開放
open class Bill{
fun getPrice(): Double {
val unit = getUnit()
val number = getNumber()
val price = unit * number
return discount(price)
}
// 處理打折優(yōu)惠
open fun discount(price: Double): Double{
return price
}
fun getUnit(): Double {
...
}
fun getNumber(): Int {
...
}
}
普通的收費方式在 discount
函數(shù)中直接返回價格
七夕節(jié)的收費方式則繼承此類
在 discount 函數(shù)中實現(xiàn)打 77折
class LoversDayBill : Bill(){
override fun discount(price: Double): Double {
return price * 0.77
}
}
老過已經(jīng)開始幻想自己將來
坐在按摩椅上的舒服日子
聽到新需求
老過一陣頭大
不由在群里吐槽
吐槽歸吐槽
老過在 getPrice 函數(shù)中
再次增加了條件判斷
作者:力扣(LeetCode)
鏈接:https://www.zhihu.com/question/31021366/answer/761614647
來源:知乎
著作權(quán)歸作者所有陨亡。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處深员。
class Bill {
fun getPrice(): Double {
val unit = getUnit()
val number = getNumber()
val price = unit * number
if (todayIsLoversDay()) {
return price * 0.77
}
if (todayIsMiddleAutumn() && price > 399) {
return price - 200
}
if (todayIsNationalDay() && price < 100) {
// 生成 0 ~ 9 隨機數(shù)字负蠕,如果為 0 則免單。即:十分之一概率免單
val free = Random().nextInt(10)
if (free == 0) {
return 0.0
}
}
return price
}
fun getUnit(): Double {
...
}
fun getNumber(): Int {
...
}
fun todayIsLoversDay(): Boolean {
...
}
fun todayIsMiddleAutumn(): Boolean {
...
}
fun todayIsNationalDay(): Boolean {
...
}
}
看著越來越復(fù)雜的
Bill 類和 getPrice 方法
老過眉頭緊鎖
他深知事情遠沒有結(jié)束
中秋和國慶一過
他還需要到這個復(fù)雜的類中
刪掉打折的方法
天知道老板還會再提
什么天馬行空的需求
無論是新增或刪除代碼倦畅,在這個過長的類里做修改都是件不太愉快的事遮糖。為了在一個很長的函數(shù)中找到需要修改的位置,「面向過程」使得老過不得不瀏覽大量與修改無關(guān)的代碼叠赐,小心翼翼地修改后欲账,又要反復(fù)確認不會影響到類的其他部分。
老過在心底里默默地祈禱
這個類不再需要修改
提交了自己的程序
阿對收到新需求時
先是新增了中秋節(jié)支付類
class MiddleAutumePrice : Bill() {
override fun discount(price: Double): Double {
if (price > 399) {
return price - 200
}
return super.discount(price)
}
}
再增加了國慶節(jié)支付類:
class NationalDayBill : Bill() {
override fun discount(price: Double): Double {
if (price < 100) {
// 生成 0 ~ 9 隨機數(shù)字芭概,如果為 0 則免單赛不。即:十分之一概率免單
val free = Random().nextInt(10)
if (free == 0) {
return 0.0
}
}
return super.discount(price)
}
}
「面向?qū)ο蟆棺尠ψ钕矚g的一點是
有一個好消息要告訴大家!
當老板興高采烈地說出這句話時
老過和阿對都露出了心驚膽戰(zhàn)的表情
這句話往往意味著要更改需求
老過反抗道
但他并沒有說出心里另一個小九九
實在不想再去給 Bill 類添加代碼了
這次修改老過花了較長的時間才完成
class Bill {
val gifts = listOf("flower", "chocolate", "9.9 discount")
fun getPrice(): Double {
val unit = getUnit()
val number = getNumber()
val price = unit * number
if (todayIsLoversDay() && isCouple()) {
if (price > 99) {
val lucky = Random().nextInt(gifts.size)
println("Congratulations on getting ${gifts[lucky]}!")
}
return price * 0.77
}
if (todayIsMiddleAutumn() && price > 399) {
return price - 200
}
if (todayIsNationalDay() && price < 100) {
// 生成 0 ~ 9 隨機數(shù)字罢洲,如果為 0 則免單踢故。即:十分之一概率免單
val free = Random().nextInt(10)
if (free == 0) {
return 0.0
}
}
return price
}
fun getUnit(): Double {
...
}
fun getNumber(): Int {
...
}
fun todayIsLoversDay(): Boolean {
...
}
private fun isCouple(): Boolean {
...
}
fun todayIsMiddleAutumn(): Boolean {
...
}
fun todayIsNationalDay(): Boolean {
...
}
}
看著那個只屬于七夕節(jié)的 gifts 變量
老過像看著自己白襯衫上的油漬一樣難受
以后每次收費時都會生成一個
只有七夕節(jié)才會用到的變量
都是因為老板的需求太奇葩
才讓這個程序看起來亂糟糟的
由于這個類做了修改
本來已經(jīng)測試通過的代碼又得重測一遍
阿對打開了 LoversDayBill 類
將其修改如下
class LoversDayBill : Bill() {
val gifts = listOf("flower", "chocolate", "9.9 discount")
override fun discount(price: Double): Double {
if (!isCouple()) return price
if (price > 99) {
val lucky = Random().nextInt(gifts.size)
println("Congratulations on getting ${gifts[lucky]}!")
}
return price * 0.77
}
fun isCouple(): Boolean {
...
}
}
當老板看完老過和阿對的代碼后
再次興奮地提出新需求時
老過頓時暈了過去......
比賽真是太焦灼了
最后贏得獎勵的是?
第三個參賽者
老板的傻兒子
他完全不會寫程序
但他使用 Ctrl+C,Ctrl+V
拷貝了阿對的代碼
3. 面試常見考點
在面試中畴椰,面向?qū)ο蟮某R娍疾禳c是三個基本特征:封裝臊诊、繼承、多態(tài)斜脂。
- 封裝:也就是把客觀事物封裝成抽象的類抓艳,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏帚戳。
- 繼承 :繼承是指這樣一種能力:它可以使用現(xiàn)有類的所有功能玷或,并在無需重新編寫原來類的情況下對這些功能進行擴展。通過繼承創(chuàng)建的新類稱為「子類」或「派生類」片任,被繼承的類稱為「基類」偏友、「父類」或「超類」。 要實現(xiàn)繼承对供,可以通過 繼承和組合 來實現(xiàn)位他。
- 多態(tài)性 多態(tài)性是允許你將父對象設(shè)置成為和一個或更多的他的子對象相等的技術(shù),賦值之后产场,父對象就可以根據(jù)當前賦值給它的子對象的特性以不同的方式運作鹅髓。簡單說就是一句話:允許將子類類型的指針賦值給父類類型的指針。 實現(xiàn)多態(tài)京景,有兩種方式窿冯,覆蓋和重載。兩者的區(qū)別在于:覆蓋在運行時決定确徙,重載是在編譯時決定醒串。并且覆蓋和重載的機制不同。例如在 Java 中鄙皇,重載方法的簽名必須不同于原先方法的芜赌,但對于覆蓋簽名必須相同。
面向?qū)ο蟮木幊谭绞绞沟妹恳粋€類都只做一件事育苟。面向過程會讓一個類越來越全能较鼓,就像一個管家一樣做了所有的事椎木。而面向?qū)ο笙袷枪蛡蛄艘蝗郝殕T违柏,每個人做一件小事,各司其職香椎,最終合作共贏漱竖。
面向?qū)ο蟮淖龇ù_實是把屬性和功能封裝起來,但是其核心是歸類和抽象畜伐。
把相關(guān)的屬性和功能集中起來馍惹,把可以分離的部分隔絕開來立帖,從而把復(fù)雜的業(yè)務(wù)邏輯切割成互相之間可以相對獨立的部分,降低開發(fā)的難度急鳄。
所以面向?qū)ο蠼^對不僅僅是弄一個class然后把一堆東西往里面塞银酗,真正重要的是判斷需要構(gòu)造哪些class,它們之間的關(guān)聯(lián)良狈,以及把什么東西往哪一個里面塞后添。