淺談設計模式之結構型模式
前言
通過學習設計模式,我們知道根據目的、用途的不同,把設計模式分為建立型模式、結構型模式、行為型模式。
- 建立型模式主要用于建立對象;
- 結構型模式主要用于處理類和對象的組合;
- 行為型模式主要用于描述類或對象的互動以及職責配置設定
本篇,我想對結構型模式進行一番總結、探讨。
認識結構型模式
結構型模式所描述的是如何将類和對象結合在一起來形成一個更大的結構,它描述兩種不同的事物:類和對象,根據這一點,可分為類結構型和對象結構型模式。類結構型模式關心類的組合,由多個類可以組合成一個更大的系統,在類結構型模式中一般隻存在繼承關系和實作關系;對象結構型模式關心類與對象的組合,通過關聯關系使得在一個類中定義另一個類的執行個體對象,然後通過該對象調用其方法。根據“合成複用原則”,在系統中盡量使用關聯關系來替代繼承關系,是以大部分結構型模式都是對象結構型模式
結構型模式的執行個體
- 擴充卡模式:将一個類的接口轉換成客戶希望的另外一種接口,這樣就能實作已有接口的複用。擴充卡主要有類擴充卡和對象擴充卡兩種實作方式,通常情況下,推薦優先使用對象擴充卡方式。
- 橋接模式:将抽象部分與實作部分分離,使它們都可以獨立地變化。它主要用于應對多元度變化點問題,通過對象組合的方式,可以極大地減少子類的數目,同時還能讓不同次元獨立擴充變化。
- 組合模式:将對象組合成樹形結構以表示“整合-部分”的層次結構,進而使得使用者對單個對象群組合對象的使用具有一緻性,也就是用戶端能夠透明地無差別地操作兩者。
- 裝飾模式:動态地給一個對象添加一些額外的職責,就增加功能來說,裝飾模式相比生成子類更為靈活。假若使用多繼承的方式來完成職責的添加,将會不可避免地造成子類數目的“爆炸性”增長,此外,因為是靜态增加的,那也就不可能在運作狀态時動态地添加或者删除額外職責呢。
- 外觀模式:為子系統中的一組接口提供一個一緻的接口,外觀模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。這樣原來需要客戶直接與複雜的子系統打交道、互動,現在這一過程将完全将交由外觀對象來完成,極大地友善了用戶端的調用。
- 享元模式:運用共享技術有效地支援大量細粒度的對象。享元模式關鍵是将對象的内部狀态和外部狀态分離,盡可能地對“穩定”的内部狀态進行共享,而将會随運用場景而改變的狀态通過外部狀态傳入。
- 代理模式:為其他對象提供一種代理以控制對這個對象的通路。主要是在用戶端和目标對象間增加一層間接層,通過這個間接層來完成對目标對象的種種控制操作,是以也就形成了不同功能類型的代理呢,比如遠端代理、保護代理和虛代理等等。
- ···
以擴充卡模式為例,代碼解析
說到擴充卡,我們最熟悉的莫過于電源擴充卡了,也就是手機的充電頭。它就是擴充卡模式的一個應用。
大家可以試想一下,如果你有一條連接配接電腦和手機的 USB 資料線,連接配接電腦的一端從電腦接口處接收 5V 的電壓,連接配接手機的一端向手機輸出 5V 的電壓,并且它們都工作良好。
我們常用的家用電壓都是 220V,是以 USB 資料線不能直接拿來給手機充電,這時候我們有兩種方案:
- 一、單獨制作手機充電器,接收 220V 家用電壓,輸出 5V 電壓。
- 二、添加一個擴充卡,将 220V 家庭電壓轉化為類似電腦接口的 5V 電壓,再連接配接資料線給手機充電。
如果你使用過早期的手機,就會知道以前的手機廠商采用的就是第一種方案:早期的手機充電器都是單獨制作的,充電頭和充電線是連在一起的,但現在的手機都采用了電源擴充卡加資料線的方案。
現在我要說的擴充卡模式,就是将一個類的接口轉換成客戶希望的另外一個接口,使得原本由于接口不相容而不能一起工作的那些類能一起工作。
适配的意思是适應、比對。通俗地講,擴充卡模式适用于有相關性但不相容的結構,源接口通過一個中間件轉換後才可以适用于目标接口,這個轉換過程就是适配,這個中間件就稱之為擴充卡。
家用電源和 USB 資料線有相關性:家用電源輸出電壓,USB 資料線輸入電壓。但兩個接口無法相容,因為一個輸出 220V,一個輸入 5V,通過擴充卡将輸出 220V 轉換成輸出 5V 之後才可以一起工作。
接下來,我用程式模拟一下這個過程:
家庭電源提供220V的電壓
HomeBattery類:
class HomeBattery {
int supply() {
// 家用電源提供一個 220V 的輸出電壓
return 220;
}
}
複制代碼
USB 資料線隻接收 5V 的充電電壓
USBLine類:
class USBLine {
void charge(int volt) {
// 如果電壓不是 5V,抛出異常
if (volt != 5) throw new IllegalArgumentException("隻能接收 5V 電壓");
// 如果電壓是 5V,正常充電
System.out.println("正常充電");
}
}
複制代碼
先來看看适配之前,使用者如果直接用家庭電源給手機充電:
User類
public class User {
@Test
public void chargeForPhone() {
HomeBattery homeBattery = new HomeBattery();
int homeVolt = homeBattery.supply();
System.out.println("家庭電源提供的電壓是 " + homeVolt + "V");
USBLine usbLine = new USBLine();
usbLine.charge(homeVolt);
}
}
複制代碼
運作結果如下:
家庭電源提供的電壓是 220V
java.lang.IllegalArgumentException: 隻能接收 5V 電壓
這時,如果加入電源擴充卡:
Adapter類
class Adapter {
int convert(int homeVolt) {
// 适配過程:使用電阻、電容等器件将其降低為輸出 5V
int chargeVolt = homeVolt - 215;
return chargeVolt;
}
}
複制代碼
然後,使用者再使用擴充卡将家庭電源提供的電壓轉換為充電電壓:
public class User {
@Test
public void chargeForPhone() {
HomeBattery homeBattery = new HomeBattery();
int homeVolt = homeBattery.supply();
System.out.println("家庭電源提供的電壓是 " + homeVolt + "V");
Adapter adapter = new Adapter();
int chargeVolt = adapter.convert(homeVolt);
System.out.println("使用擴充卡将家庭電壓轉換成了 " + chargeVolt + "V");
USBLine usbLine = new USBLine();
usbLine.charge(chargeVolt);
}
}
複制代碼
使用擴充卡将家庭電壓轉換成了 5V
正常充電
這就是擴充卡模式。在我們日常的開發中經常會使用到各種各樣的 Adapter,都屬于擴充卡模式的應用。
但擴充卡模式并不推薦多用。因為未雨綢缪好過亡羊補牢,如果事先能預防接口不同的問題,不比對問題就不會發生,隻有遇到源接口無法改變時,才應該考慮使用擴充卡。比如現代的電源插口中很多已經增加了專門的充電接口,讓我們不需要再使用擴充卡轉換接口,這又是社會的一個進步。
總結
以上内容是我對結構型模式做的一次簡單的總結,讓大家對結構型模式整體上有一些了解和認識,文中我以結構型模式中的擴充卡模式為例,進行了代碼示範,也能讓大家進一步進行了解結構型模式,程式是一個不斷改進的過程,希望我們學了設計模式之後能夠學以緻用,優化自己的程式。

:泰鬥賢若如
微信公衆号:見賢思程式設計
Github:https://github.com/zyx110
有事微信:zyxt1637039050
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連結,否則保留追究法律責任的權利。
我不能保證我所說的都是對的,但我能保證每一篇都是用心去寫的,我始終認同: “
分享的越多,你的價值增值越大”,我們一同在分享中進步,在分享中成長,
越努力越幸運。再分享一句話“
十年前你是誰,一年前你是誰,甚至昨天你是誰,都不重要。重要的是,今天你是誰,以及明天你将成為誰。”
人生赢在轉折處,改變從現在開始!支援我的朋友們記得點波
推薦哦,您的肯定就是我前進的動力。