設計模式文章集合:http://aphysia.cn/categories/designpattern
開局一張圖,剩下全靠寫...
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5iR4UyQCVSNFVSMBVCOBViNFVSMBVSRBVCOFVSRCVSRBVCOFVyLcd2bsJ2Lc12bj5ycj5Wd5lGbh5ybhR2ZulWct42YtM3cv5SZyVHdjlGcud3bktmch12Lc9CX6MHc0RHaiojIsJye.png)
介紹
擴充卡模式(百度百科):在計算機程式設計中,擴充卡模式(有時候也稱包裝樣式或者包裝)将一個類的接口适配成使用者所期待的。一個适配允許通常因為接口不相容而不能在一起工作的類工作在一起,做法是将類自己的接口包裹在一個已存在的類中。
擴充卡模式的主要目的就是為了相容性,把原來不比對的兩個類或者接口可以協同工作,它屬于結構型模式,主要分為三種:類擴充卡,對象擴充卡,接口擴充卡。
擴充卡模式靈活性比較好,可以提高複用性,但是如果濫用,系統調用關系會比較複雜,每一次的适配,本質上都是一種妥協。
不斷妥協,最後迎來的,必定是重構。
擴充卡模式類型
類擴充卡
描述:擴充卡的類(
Adapter
),通過繼承原有類,同時實作目标接口,完成的功能是擁有原有類的屬性方法,同時可以調用目标接口。
例子:原來一種充電器(目标類)可以給
IPhone
充電,另一種充電器(接口)可以給
Android
手機充電,我們想實作一種擴充卡可以讓
IPhone
充電器擁有
Android
充電器的功能。
代碼結構如下:
-
:AndroidCharger.class
//給android充電的接口
public interface AndroidCharger {
public void androidout();
}
-
AppleCharger.class
//給蘋果充電的類
public class AppleCharger {
public void iphoenOut(){
System.out.println("我是充電器,我可以給蘋果充電...");
}
}
-
ChagerAdapater.class
//充電擴充卡
public class ChagerAdapater extends AppleCharger implements AndroidCharger {
@Override
public void androidout() {
iphoenOut();
System.out.println("擴充卡開始工作----");
System.out.print("我擁有了給Android充電的能力");
}
}
-
Test.class
public class Test {
public static void main(String[]args){
ChagerAdapater chagerAdapater = new ChagerAdapater();
chagerAdapater.androidout();
}
}
運作結果如下:
個人了解:這裡之是以一個繼承一個接口,是因為java隻能單繼承,要去适配多個類,隻能一個繼承,一個用接口實作,有一定局限性。重寫它的方法,這也比較靈活,可以對接口方法進行修改。
2.對象擴充卡
個人了解:上面所說的類擴充卡是通過繼承與實作接口的方式實作(所繼承的父類以及接口都是一個
class
),對象擴充卡就是根據“合成複用原則”,不使用繼承關系,而是使用了關聯關系,直接把另一個類的對象當成成員對象,也就是持有之前需要繼承的類的執行個體。
代碼結構沒有改變,隻是重新建立了一個包:
- 更改後的
ChagerAdapater.class
//充電擴充卡
public class ChagerAdapater implements AndroidCharger {
//持有蘋果充電器的執行個體
private AppleCharger appleCharger;
//構造器
public ChagerAdapater(AppleCharger appleCharger){
this.appleCharger = appleCharger;
}
@Override
public void androidout() {
System.out.println("擴充卡開始工作----");
System.out.print("我擁有了給Android充電的能力");
}
}
- 更改後的 Test.class
public class Test {
public static void main(String[]args){
ChagerAdapater chagerAdapater = new ChagerAdapater(new AppleCharger());
chagerAdapater.androidout();
}
}
運作結果沒有改變:
- 個人了解:這個和第一種類的擴充卡其實思想上差不多,隻是實作的方式不一樣,類擴充卡是通過繼承類,實作接口,對象擴充卡是把要繼承的類變成了屬性對象,把執行個體與擴充卡關聯起來,也就是擴充卡的類持有了原有父類的對象執行個體。一般而言,由于
是單繼承,是以我們盡量不要把這一次使用繼承的機會給浪費了,這樣寫也比較靈活。
java
3.接口擴充卡
接口擴充卡,也可以稱為預設擴充卡模式,或者預設擴充卡模式。當我們不需要全部實作接口所實作的方法的時候,我們可以設計一個抽象類去實作接口,然後再這個抽象類中為所有方法提供一個預設的實作,這個抽象類的子類就可以有選擇地對方法進行實作了。
解釋:
學生類
可以吃飯,學習,但是
教師類
也吃飯,但是教師不是學習,而是教書,是以我們把
學習
,
吃飯
教書
當成接口的方法,由于不是所有的類都需要實作所有接口,我們在中間實作了一個抽象類實作這些接口,所有的方法都提供了一個預設是實作方法。然後學生類或者教師類才去繼承抽象類,進而實作自己所需要的一部分方法即可。
-
myInterface.class
//定義接口的方法
public interface myInterface {
//學習的接口方法
public void study();
//教書的接口方法
public void teach();
//吃飯的接口方法
public void eat();
}
-
myAbstractClass.class(抽象類)
public abstract class myAbstractClass implements myInterface{
//學習的接口方法
@Override
public void study(){}
@Override
//吃飯的接口方法
public void eat(){}
//教書的接口方法
@Override
public void teach(){}
}
-
Student.class(學生類)
public class Student extends myAbstractClass{
//學習的接口方法
@Override
public void study(){
System.out.println("我是學生,我要好好學習");
}
@Override
//吃飯的接口方法
public void eat(){
System.out.println("我是學生,我要吃飯");
}
}
-
Teacher.class(教師類)
public class Teacher extends myAbstractClass {
@Override
//吃飯的接口方法
public void eat(){
System.out.println("我是教師,我要吃飯");
}
//教書的接口方法
@Override
public void teach(){
System.out.println("我是教師,我要教育祖國的花朵");
}
}
-
Test.calss(測試類)
public class Test {
public static void main(String[] args){
Student student = new Student();
Teacher teacher = new Teacher();
student.eat();
student.study();
teacher.eat();
teacher.teach();
}
}
運作的結果:
4.總結
1.類擴充卡模式主要是通過繼承目标的類,實作要增加的接口方法,就可以把類與接口适配一起工作。
2.對象的擴充卡與類擴充卡功能大緻一樣,但是為了更加靈活,不再使用繼承的方式,而是直接使用了成員變量這樣的方法,将目标的類的對象持有,再實作要增加的接口方法,達到一樣的目的。
3.接口擴充卡模式,是把所有的方法定義到一個接口裡面,然後建立一個抽象類去實作所有的方法,再使用真正的類去繼承抽象類,隻需要重寫需要的方法,就可以完成适配的功能。
如果有興趣,可以了解一下另外一種說法的擴充卡模式[https://blog.csdn.net/Aphysia/article/details/80292049]
4.建議盡量使用對象的擴充卡模式,少用繼承。擴充卡模式也是一種包裝模式,它與裝飾模式同樣具有包裝的功能,此外,對象擴充卡模式還具有委托的意思。總的來說,擴充卡模式屬于補償模式,專門用來在系統後期擴充、修改時使用,但要注意不要過度使用擴充卡模式。
【作者簡介】:
秦懷,公衆号【秦懷雜貨店】作者,技術之路不在一時,山高水長,縱使緩慢,馳而不息。個人寫作方向:
Java源碼解析
JDBC
Mybatis
Spring
redis
分布式
劍指Offer
LeetCode
等,認真寫好每一篇文章,不喜歡标題黨,不喜歡花裡胡哨,大多寫系列文章,不能保證我寫的都完全正确,但是我保證所寫的均經過實踐或者查找資料。遺漏或者錯誤之處,還望指正。
劍指Offer全部題解PDF
2020年我寫了什麼?
開源程式設計筆記
關注公衆号 ”秦懷雜貨店“ 可以領取版本的
劍指 Offer V1
解法,V2版本增加了題目,還在哼哧哼哧的更新中,并且為每道題目增加了
解法,敬請期待。
C++