需求:假設要設計一個電腦商場管理系統的某個模塊設計,電腦分爲品牌和類型兩個緯度,咱們應該怎麼解決?html
按照初學者的思路,利用繼承就能簡單粗暴的實現,那咱們來看下這種思路的設計類圖。
設計模式
從電腦緯度劃分微信
package com.aaron.bridge; public interface Computer { public void sale(); } class Desktop implements Computer{ @Override public void sale() { System.out.println("臺式電腦"); } } class Laptop implements Computer{ @Override public void sale() { System.out.println("筆記本電腦"); } } class Pad implements Computer{ @Override public void sale() { System.out.println("平板電腦"); } }
從品牌緯度劃分ide
package com.aaron.bridge; // 宏碁品牌的三種類型 public class AcerDesktop extends Desktop{ @Override public void sale() { System.out.println("宏碁臺式機"); } } class AcerLaptop extends Laptop{ @Override public void sale() { System.out.println("宏碁筆記本電腦"); } } class AcerPad extends Pad{ @Override public void sale() { System.out.println("宏碁平板電腦"); } }
package com.aaron.bridge; // 蘋果品牌的三種類型 public class AppleDesktop extends Desktop{ @Override public void sale() { System.out.println("蘋果臺式機"); } } class AppleLaptop extends Laptop{ @Override public void sale() { System.out.println("蘋果筆記本電腦"); } } class ApplePad extends Pad{ @Override public void sale() { System.out.println("蘋果平板電腦"); } }
package com.aaron.bridge; //戴爾品牌的三種類型 public class DellDesktop extends Desktop{ @Override public void sale() { System.out.println("戴爾臺式機"); } } class DellLaptop extends Laptop{ @Override public void sale() { System.out.println("戴爾筆記本電腦"); } } class DellPad extends Pad{ @Override public void sale() { System.out.println("戴爾平板電腦"); } }
問題1:假設咱們的系統按照上述思路設計,當咱們新增一個品牌的時候,怎麼辦?函數
根據上述思路,從品牌緯度擴展品牌時直接新增臺式機、筆記本電腦、平板電腦的類便可。this
問題2:當咱們新增一個機器類型的時候又該怎麼辦?
根據上述思路,在機器緯度類型擴展。設計
package com.aaron.bridge; // 電腦緯度 public interface Computer { public void sale(); } class Desktop implements Computer{ @Override public void sale() { System.out.println("臺式電腦"); } } class Laptop implements Computer{ @Override public void sale() { System.out.println("筆記本電腦"); } } class Pad implements Computer{ @Override public void sale() { System.out.println("平板電腦"); } } class MaxPad implements Computer{ @Override public void sale() { System.out.println("超大屏電腦"); } } // 品牌緯度 public class DellDesktop extends Desktop{ @Override public void sale() { System.out.println("戴爾臺式機"); } } class DellLaptop extends Laptop{ @Override public void sale() { System.out.println("戴爾筆記本電腦"); } } class DellPad extends Pad{ @Override public void sale() { System.out.println("戴爾平板電腦"); } } class DellPad extends Pad{ @Override public void sale() { System.out.println("戴爾平板電腦"); } } class DellMaxPad extends Pad{ @Override public void sale() { System.out.println("超大屏平板電腦"); } }
思考:當咱們添加少許的機型和品牌的時候,該方案的代碼擴展性仍是能夠接受的。可是,再往遠思考一步。code
問題:上述問題主要是把電腦和品牌兩個緯度耦合。htm
解決:將機器、品牌兩個緯度進行拆分,不要將他們耦合。對象
將兩個維度(抽象、實現)分離,使它們均可以獨立地變化。
關鍵:將上述問題拆分紅兩個緯度類型和品牌。咱們剛剛也討論了,主要解決拓展性問題。當添加一個新的機器類型或者品牌的時候,不會對其餘機器類型或者品牌產生影響。
概念:簡單談下概念,重點根據類圖和實現代碼去理解Abstraction、RefinedAbstraction、Implementor、ConcreteImplementor
Abstraction:抽象部分的接口。一般在這個對象裏面,要維護一個實現部分的對象引用,在抽象對象裏面的方法,須要調用實現部分的對象來完成。這個對象裏面的方法,一般都是跟具體的業務相關的方法。
RefinedAbstraction:
擴展抽象部分的接口,一般在這些對象裏面,定義跟實際業務相關的方法,這些方法的實現一般會使用Abstraction中定義的方法,也可能須要調用實現部分的對象來完成。
Implementor:
定義實現部分的接口,這個接口不用和Abstraction裏面的方法一致(根據約定優於配置原則,建議跟Abstraction一致。),一般是由Implementor接口提供基本的操做,而Abstraction裏面定義的是基於這些基本操做的業務方法,也就是說Abstraction定義了基於這些基本操做的較高層次的操做。
ConcreteImplementor:
真正實現Implementor接口的對象。
一、實體部分設計
package com.aaron.bridge; /** * * @author xiaoyongAaron * 品牌緯度-實現部分接口 */ public interface ImplementorBrand { public void sale(); } class ConcreteImplementorAcer implements ImplementorBrand{ @Override public void sale() { System.out.println("宏碁品牌"); } } class ConcreteImplementorApple implements ImplementorBrand{ @Override public void sale() { System.out.println("蘋果品牌"); } } class ConcreteImplementorDell implements ImplementorBrand{ @Override public void sale() { System.out.println("戴爾品牌"); } }
二、抽象部分設計
package com.aaron.bridge; /** * 機器類型緯度-抽象部分 * @author xiaoyongAaron */ public class AbstractionComputer { protected ImplementorBrand brand; public AbstractionComputer(ImplementorBrand brand){ this.brand=brand; } public void sale(){ brand.sale(); }; } /** * 擴展部分 * @author xiaoyongAaron */ class RefinedAbstractionDesktop extends AbstractionComputer{ public RefinedAbstractionDesktop(ImplementorBrand brand) { super(brand); } @Override public void sale() { //添加本身的特性,實際業務。 paly(); super.sale(); } public void paly(){ System.out.println("我臺式機抗摔打"); } } class RefinedAbstractionLaptop extends AbstractionComputer{ public RefinedAbstractionLaptop(ImplementorBrand brand) { super(brand); } @Override public void sale() { //添加本身的特性,實際業務。 lighting(); super.sale(); } public void lighting(){ System.out.println("我筆記本電腦充電5分鐘,續航5小時"); } } class RefinedAbstractionPad extends AbstractionComputer{ public RefinedAbstractionPad(ImplementorBrand brand) { super(brand); } @Override public void sale() { //添加本身的特性,實際業務。 weighting(); super.sale(); } public void weighting(){ System.out.println("我平板電腦便於攜帶"); } }
四、執行結果顯示
簡單說橋接模式就是把兩個緯度分離,因此說當咱們在實際開發的時候,遇到兩個維度問題的時候,直接條件反射橋接模式。
就像上述問題,當有兩個維度(品牌+機器類型)賦予給一個類的時候,基於單一職責原則,須要把它們解耦。那經過上述範例可知,那麼咱們就須要一座橋同樣,把兩個緯度用一箇中間物(類或者接口)把它們關聯起來,從而達到咱們的目的。
核心:如何把Implementor對象傳遞到抽象接口。
實際應用場景:
做者:碼農皮邱
原文:https://www.cnblogs.com/qiuyong/p/11107180.html
推薦:您的支持是對博主深刻思考總結的最大鼓勵,要是有須要關注公衆號與做者面對面對話交流~
說明:本文版權歸做者全部,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文連接,尊重做者的勞動成果。