理論二:封裝、抽象、繼承、多態(tài)分別可以解決哪些編程問(wèn)題?

封裝(Encapsulation)
首先,我們來(lái)看封裝特性。封裝也叫作信息隱藏或者數(shù)據(jù)訪問(wèn)保護(hù)。類通過(guò)暴露有限的訪問(wèn)接口,授權(quán)外部?jī)H能通過(guò)類提供的方式(或者叫函數(shù))來(lái)訪問(wèn)內(nèi)部信息或者數(shù)據(jù)。

下面這段代碼是金融系統(tǒng)中一個(gè)簡(jiǎn)化版的虛擬錢包的代碼實(shí)現(xiàn):

public class Wallet {
private String id;
private long createTime;
private BigDecimal balance;
private long balanceLastModifiedTime;
// ...省略其他屬性...

public Wallet() {
this.id = IdGenerator.getInstance().generate();
this.createTime = System.currentTimeMillis();
this.balance = BigDecimal.ZERO;
this.balanceLastModifiedTime = System.currentTimeMillis();
}

// 注意:下面對(duì)get方法做了代碼折疊,是為了減少代碼所占文章的篇幅
public String getId() { return this.id; }
public long getCreateTime() { return this.createTime; }
public BigDecimal getBalance() { return this.balance; }
public long getBalanceLastModifiedTime() { return this.balanceLastModifiedTime; }

public void increaseBalance(BigDecimal increasedAmount) {
if (increasedAmount.compareTo(BigDecimal.ZERO) < 0) {
throw new InvalidAmountException("...");
}
this.balance.add(increasedAmount);
this.balanceLastModifiedTime = System.currentTimeMillis();
}

public void decreaseBalance(BigDecimal decreasedAmount) {
if (decreasedAmount.compareTo(BigDecimal.ZERO) < 0) {
throw new InvalidAmountException("...");
}
if (decreasedAmount.compareTo(this.balance) > 0) {
throw new InsufficientAmountException("...");
}
this.balance.subtract(decreasedAmount);
this.balanceLastModifiedTime = System.currentTimeMillis();
}
}

Wallet 類主要有四個(gè)屬性(也可以叫作成員變量),也就是我們前面定義中提到的信息或者數(shù)據(jù)。其中,id 表示錢包的唯一編號(hào),createTime 表示錢包創(chuàng)建的時(shí)間,balance 表示錢包中的余額,balanceLastModifiedTime 表示上次錢包余額變更的時(shí)間。

參照封裝特性,對(duì)錢包的這四個(gè)屬性的訪問(wèn)方式進(jìn)行了限制。調(diào)用者只允許通過(guò)下面這六個(gè)方法來(lái)訪問(wèn)或者修改錢包里的數(shù)據(jù)。String getId()long getCreateTime()BigDecimal getBalance()long getBalanceLastModifiedTime()void increaseBalance(BigDecimal increasedAmount)void decreaseBalance(BigDecimal decreasedAmount)

對(duì)于封裝這個(gè)特性,我們需要編程語(yǔ)言本身提供一定的語(yǔ)法機(jī)制來(lái)支持。這個(gè)語(yǔ)法機(jī)制就是訪問(wèn)權(quán)限控制。

抽象(Abstraction)
封裝主要講的是如何隱藏信息、保護(hù)數(shù)據(jù),而抽象講的是如何隱藏方法的具體實(shí)現(xiàn),讓調(diào)用者只需要關(guān)心方法提供了哪些功能,并不需要知道這些功能是如何實(shí)現(xiàn)的。

我們利用 Java 中的 interface 接口語(yǔ)法來(lái)實(shí)現(xiàn)抽象特性。調(diào)用者在使用圖片存儲(chǔ)功能的時(shí)候,只需要了解 IPictureStorage 這個(gè)接口類暴露了哪些方法就可以了,不需要去查看 PictureStorage 類里的具體實(shí)現(xiàn)邏輯:
public interface IPictureStorage {
void savePicture(Picture picture);
Image getPicture(String pictureId);
void deletePicture(String pictureId);
void modifyMetaInfo(String pictureId, PictureMetaInfo metaInfo);
}

public class PictureStorage implements IPictureStorage {
// ...省略其他屬性...
@Override
public void savePicture(Picture picture) { ... }
@Override
public Image getPicture(String pictureId) { ... }
@Override
public void deletePicture(String pictureId) { ... }
@Override
public void modifyMetaInfo(String pictureId, PictureMetaInfo metaInfo) { ... }
}

抽象這個(gè)概念是一個(gè)非常通用的設(shè)計(jì)思想,并不單單用在面向?qū)ο缶幊讨校部梢杂脕?lái)指導(dǎo)架構(gòu)設(shè)計(jì)等。而且這個(gè)特性也并不需要編程語(yǔ)言提供特殊的語(yǔ)法機(jī)制來(lái)支持,只需要提供“函數(shù)”這一非?;A(chǔ)的語(yǔ)法機(jī)制,就可以實(shí)現(xiàn)抽象特性、所以,它沒(méi)有很強(qiáng)的“特異性”,有時(shí)候并不被看作面向?qū)ο缶幊痰奶匦灾弧?/p>

繼承(Inheritance)
繼承是用來(lái)表示類之間的 is-a 關(guān)系,比如貓是一種哺乳動(dòng)物。從繼承關(guān)系上來(lái)講,繼承可以分為兩種模式,單繼承和多繼承。單繼承表示一個(gè)子類只繼承一個(gè)父類,多繼承表示一個(gè)子類可以繼承多個(gè)父類,比如貓既是哺乳動(dòng)物,又是爬行動(dòng)物。

多態(tài)(Polymorphism)
多態(tài)是指,子類可以替換父類,在實(shí)際的代碼運(yùn)行過(guò)程中,調(diào)用子類的方法實(shí)現(xiàn)。

public class DynamicArray {
private static final int DEFAULT_CAPACITY = 10;
protected int size = 0;
protected int capacity = DEFAULT_CAPACITY;
protected Integer[] elements = new Integer[DEFAULT_CAPACITY];

public int size() { return this.size; }
public Integer get(int index) { return elements[index];}
//...省略n多方法...

public void add(Integer e) {
ensureCapacity();
elements[size++] = e;
}

protected void ensureCapacity() {
//...如果數(shù)組滿了就擴(kuò)容...代碼省略...
}
}

public class SortedDynamicArray extends DynamicArray {
@Override
public void add(Integer e) {
ensureCapacity();
int i;
for (i = size-1; i>=0; --i) { //保證數(shù)組中的數(shù)據(jù)有序
if (elements[i] > e) {
elements[i+1] = elements[i];
} else {
break;
}
}
elements[i+1] = e;
++size;
}
}

public class Example {
public static void test(DynamicArray dynamicArray) {
dynamicArray.add(5);
dynamicArray.add(1);
dynamicArray.add(3);
for (int i = 0; i < dynamicArray.size(); ++i) {
System.out.println(dynamicArray.get(i));
}
}

public static void main(String args[]) {
DynamicArray dynamicArray = new SortedDynamicArray();
test(dynamicArray); // 打印結(jié)果:1、3、5
}
}

多態(tài)也是很多設(shè)計(jì)模式、設(shè)計(jì)原則、編程技巧的代碼實(shí)現(xiàn)基礎(chǔ),比如策略模式、基于接口而非實(shí)現(xiàn)編程、依賴倒置原則、里式替換原則、利用多態(tài)去掉冗長(zhǎng)的 if-else 語(yǔ)句等等。

在上面的例子中,我們用到了三個(gè)語(yǔ)法機(jī)制來(lái)實(shí)現(xiàn)多態(tài)。第一個(gè)語(yǔ)法機(jī)制是編程語(yǔ)言要支持父類對(duì)象可以引用子類對(duì)象,也就是可以將 SortedDynamicArray 傳遞給 DynamicArray。第二個(gè)語(yǔ)法機(jī)制是編程語(yǔ)言要支持繼承,也就是 SortedDynamicArray 繼承了 DynamicArray,才能將 SortedDyamicArray 傳遞給 DynamicArray。第三個(gè)語(yǔ)法機(jī)制是編程語(yǔ)言要支持子類可以重寫(override)父類中的方法,也就是 SortedDyamicArray 重寫了 DynamicArray 中的 add() 方法。

按照What/How/Why 模型梳理:

封裝

What:隱藏信息,保護(hù)數(shù)據(jù)訪問(wèn)。
How:暴露有限接口和屬性,需要編程語(yǔ)言提供訪問(wèn)控制的語(yǔ)法。
Why:提高代碼可維護(hù)性;降低接口復(fù)雜度,提高類的易用性。

抽象

What: 隱藏具體實(shí)現(xiàn),使用者只需關(guān)心功能,無(wú)需關(guān)心實(shí)現(xiàn)。
How: 通過(guò)接口類或者抽象類實(shí)現(xiàn),特殊語(yǔ)法機(jī)制非必須。
Why: 提高代碼的擴(kuò)展性、維護(hù)性;降低復(fù)雜度,減少細(xì)節(jié)負(fù)擔(dān)。

繼承

What: 表示 is-a 關(guān)系,分為單繼承和多繼承。
How: 需要編程語(yǔ)言提供特殊語(yǔ)法機(jī)制。例如 Java 的 “extends”,C++ 的 “:” 。
Why: 解決代碼復(fù)用問(wèn)題。

多態(tài)

What: 子類替換父類,在運(yùn)行時(shí)調(diào)用子類的實(shí)現(xiàn)。
How: 需要編程語(yǔ)言提供特殊的語(yǔ)法機(jī)制。比如繼承、接口類、duck-typing。
Why: 提高代碼擴(kuò)展性和復(fù)用性。

3W 模型的關(guān)鍵在于 Why,沒(méi)有 Why,其它兩個(gè)就沒(méi)有存在的意義。從四大特性可以看出,面向?qū)ο蟮慕K極目的只有一個(gè):可維護(hù)性。易擴(kuò)展、易復(fù)用,降低復(fù)雜度等等都屬于可維護(hù)性的實(shí)現(xiàn)方式

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容