攻防世界web基礎題知識點彙總
橋接模式又稱橋樑模式,屬於結構型模式,是指將抽象化 與 實現化 脫耦,使得二者可以獨立的變化。它是用組合關係代替繼承關係來實現,從而降低了抽象和實現這兩個可變維度的耦合度。
抽象化
存在於多個實體中的共同的概念性聯絡,就是抽象化,作為一個過程,抽象化就是忽略一些資訊,從而把不同的實體當作同樣的實體對待。通常情況下,一組物件如果具有相同的概念性聯絡,那麼他們就可以通過一個共同的類來描述,如果一些類具有相同的概念性聯絡,往往可以通過一個共同的抽象類來描述,在更加複雜的情況下,可以使用一個繼承關係的包括抽象類和具體子類的等級結構來描述。
實現化
抽象化給出的具體實現,就是實現化。一個類的例項就是這個類的實現化,一個具體子類是它的抽象超類的實現化。在更加複雜的情況下,實現化也可以是與抽象化等級結構相平行的等級結構,同樣可以由抽象類和具體類組成。
脫耦
所謂耦合,就是兩個實體的行為的某種強關聯,而將他們的強關聯去掉,就是脫耦。在這裡脫耦是指將抽象化和實現化之間的耦合解脫開,或者是將他們之間的強關聯改換成弱關聯。
手機已經是我們日常生活不可缺少的一環了,國內的手機有華為,小米,VIVO等幾個廠商,每個廠商旗下又有好多款不同配置的手機,接下來就以手機打電話的功能作為例子講解。
傳統方式實現打電話功能:
傳統模式如果要再加一個手機樣式(旋轉式),就需要對各個品牌新增call()的功能,這樣增加了程式碼的維護成本。
橋接模式
對於傳統模式出現的問題,使用橋接模式就可以很好的解決。
橋接模式的UML類圖如下:
從UML類圖可以看出,這個系統含有兩個等級結構:
- 有抽象化角色和擴充套件抽象化角色組成的抽象化等級結構
- 有實現化角色和具體實現化角色所組成的實現化等級結構
橋接模式所涉及到抽象化角色,擴充套件抽象化角色,實現化角色,具體實現化角色等幾種角色:
- 抽象化角色:給出定義,並儲存一個對實現化物件的引用
- 擴充套件抽象化角色:擴充套件抽象化角色、改變和擴充套件父類對抽象化的定義
- 實現化角色:這個角色給出實現化角色的介面,但不給出具體的實現,必須指出的是,這個介面不一定和抽象化角色的介面定義相同。實際上,這兩個介面可以非常不一樣,實現化角色應當只給出底層操作,而抽象化角色應當只給出基於底層操作的更高一層的操作
- 具體實現化角色:這個角色給出實現化角色介面的具體實現
例子的UML類圖:
抽象化角色:
package com.charon.bridge;
/**
* @className: Brand
* @description: 抽象化產品角色
* @author: charon
* @create: 2022-03-18 22:51
*/
public interface Brand {
void open();
void close();
void call();
}
擴充套件抽象化角色:
package com.charon.bridge;
/**
* @className: Vivo
* @description:
* @author: charon
* @create: 2022-03-18 22:55
*/
public class Vivo implements Brand {
@Override
public void open() {
System.out.println("vivo手機開機了。。。。");
}
@Override
public void close() {
System.out.println("vivo手機關機了。。。。");
}
@Override
public void call() {
System.out.println("vivo手機打電話。。。。");
}
}
package com.charon.bridge;
/**
* @className: XiaoMi
* @description:
* @author: charon
* @create: 2022-03-18 22:56
*/
public class XiaoMi implements Brand{
@Override
public void open() {
System.out.println("小米手機開機了。。。。");
}
@Override
public void close() {
System.out.println("小米手機關機了。。。。");
}
@Override
public void call() {
System.out.println("小米手機打電話。。。。");
}
}
實現化角色:
package com.charon.bridge;
/**
* @className: Phone
* @description: 實現化角色
* @author: charon
* @create: 2022-03-18 22:52
*/
public abstract class Phone {
private Brand brand;
public Phone(Brand brand) {
this.brand = brand;
}
protected void open(){
this.brand.open();
}
protected void call(){
this.brand.call();
}
protected void close(){
this.brand.close();
}
}
具體實現化角色:
package com.charon.bridge;
/**
* @className: FoldedPhone
* @description:
* @author: charon
* @create: 2022-03-18 22:57
*/
public class FoldedPhone extends Phone{
public FoldedPhone(Brand brand) {
super(brand);
}
@Override
protected void open(){
super.open();
System.out.println("摺疊樣式手機開機。。。。");
}
@Override
protected void call(){
super.call();
System.out.println("摺疊樣式手機打電話。。。。");
}
@Override
protected void close(){
super.close();
System.out.println("摺疊樣式手機關機。。。。");
}
}
package com.charon.bridge;
/**
* @className: UpRightPhone
* @description:
* @author: charon
* @create: 2022-03-18 22:59
*/
public class UpRightPhone extends Phone{
public UpRightPhone(Brand brand) {
super(brand);
}
@Override
protected void open(){
super.open();
System.out.println("直立樣式手機開機。。。。");
}
@Override
protected void call(){
super.call();
System.out.println("直立樣式手機打電話。。。。");
}
@Override
protected void close(){
super.close();
System.out.println("直立樣式手機關機。。。。");
}
}
測試:
package com.charon.bridge;
/**
* @className: Client
* @description:
* @author: charon
* @create: 2022-03-18 22:51
*/
public class Client {
public static void main(String[] args) {
// 獲取摺疊樣式手機(品牌+樣式)
FoldedPhone xiaomiFoldedPhone = new FoldedPhone(new XiaoMi());
xiaomiFoldedPhone.open();
xiaomiFoldedPhone.call();
xiaomiFoldedPhone.close();
UpRightPhone xiaomiUpRightPhone = new UpRightPhone(new XiaoMi());
xiaomiUpRightPhone.open();
xiaomiUpRightPhone.call();
xiaomiUpRightPhone.close();
}
}
如此這般,不管是新增一個產品還是新增一個樣式,程式碼的改動都非常小。
橋接模式遵循了里氏替換原則和依賴倒置原則,最終實現了開閉原則。
橋接模式的優點:
- 抽象與實現分離,從而極大的提供了系統的靈活性,讓抽象部分和實現部分獨立開來,這有助於系統進行分層設計,從而產生更好的結構化系統
- 對於系統的高層部分,只需要知道抽象部分和實現部分的介面就可以了,其他的部分有具體業務來完成
- 橋接模式提代了多層繼承方案,可以減少子類的個數,降低系統的管理和維護成本
橋接模式的缺點:
- 由於聚合關係建立在抽象層,要求開發者針對抽象化進行設計與程式設計
- 能正確地識別出系統中兩個獨立變化地維度,這增加了系統地理解與設計地難度
橋接模式的應用場景
當一個類內部具備兩種或多種變化維度時,使用橋接模式可以解耦這些變化的維度,使高層程式碼架構穩定。
橋接模式通常適用於以下場景。
- 當一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴充套件時。
- 當一個系統不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加時。
- 當一個系統需要在構件的抽象化角色和具體化角色之間增加更多的靈活性時。
橋接模式的一個常見使用場景就是替換繼承。我們知道,繼承擁有很多優點,比如,抽象、封裝、多型等,父類封裝共性,子類實現特性。繼承可以很好的實現程式碼複用(封裝)的功能,但這也是繼承的一大缺點。
因為父類擁有的方法,子類也會繼承得到,無論子類需不需要,這說明繼承具備強侵入性(父類程式碼侵入子類),同時會導致子類臃腫。因此,在設計模式中,有一個原則為優先使用組合/聚合,而不是繼承。