C語言中文網 目錄
首頁 > 設計模式 閱讀:1,684

橋接模式(Bridge模式)詳解

< 上一頁適配器模式 裝飾模式下一頁 >

在現實生活中,某些類具有兩個或多個維度的變化,如圖形既可按形狀分,又可按顏色分。如何設計類似于 Photoshop 這樣的軟件,能畫不同形狀和不同顏色的圖形呢?如果用繼承方式,m 種形狀和 n 種顏色的圖形就有 m×n 種,不但對應的子類很多,而且擴展困難。

當然,這樣的例子還有很多,如不同顏色和字體的文字、不同品牌和功率的汽車、不同性別和職業的男女、支持不同平臺和不同文件格式的媒體播放器等。如果用橋接模式就能很好地解決這些問題。

橋接模式的定義與特點

橋接(Bridge)模式的定義如下:將抽象與實現分離,使它們可以獨立變化。它是用組合關系代替繼承關系來實現,從而降低了抽象和實現這兩個可變維度的耦合度。

橋接(Bridge)模式的優點是:
  • 由于抽象與實現分離,所以擴展能力強;
  • 其實現細節對客戶透明。

缺點是:由于聚合關系建立在抽象層,要求開發者針對抽象化進行設計與編程,這增加了系統的理解與設計難度。

橋接模式的結構與實現

可以將抽象化部分與實現化部分分開,取消二者的繼承關系,改用組合關系。

1. 模式的結構

橋接(Bridge)模式包含以下主要角色。
  1. 抽象化(Abstraction)角色:定義抽象類,并包含一個對實現化對象的引用。
  2. 擴展抽象化(Refined    Abstraction)角色:是抽象化角色的子類,實現父類中的業務方法,并通過組合關系調用實現化角色中的業務方法。
  3. 實現化(Implementor)角色:定義實現化角色的接口,供擴展抽象化角色調用。
  4. 具體實現化(Concrete Implementor)角色:給出實現化角色接口的具體實現。

其結構圖如圖 1 所示。

橋接模式的結構圖
圖1 橋接模式的結構圖

2. 模式的實現

橋接模式的代碼如下:
package bridge;
public class BridgeTest
{
    public static void main(String[] args)
    {
        Implementor imple=new ConcreteImplementorA();
        Abstraction abs=new RefinedAbstraction(imple);
        abs.Operation();
    }
}
//實現化角色
interface Implementor
{
    public void OperationImpl();
}
//具體實現化角色
class ConcreteImplementorA implements Implementor
{
    public void OperationImpl()
    {
        System.out.println("具體實現化(Concrete Implementor)角色被訪問" );
    }
}
//抽象化角色
abstract class Abstraction
{
   protected Implementor imple;
   protected Abstraction(Implementor imple)
   {
       this.imple=imple;
   }
   public abstract void Operation();   
}
//擴展抽象化角色
class RefinedAbstraction extends Abstraction
{
   protected RefinedAbstraction(Implementor imple)
   {
       super(imple);
   }
   public void Operation()
   {
       System.out.println("擴展抽象化(Refined Abstraction)角色被訪問" );
       imple.OperationImpl();
   }
}

程序的運行結果如下:
擴展抽象化(Refined Abstraction)角色被訪問
具體實現化(Concrete Implementor)角色被訪問

橋接模式的應用實例

【例1】用橋接(Bridge)模式模擬女士皮包的選購。

分析:女士皮包有很多種,可以按用途分、按皮質分、按品牌分、按顏色分、按大小分等,存在多個維度的變化,所以采用橋接模式來實現女士皮包的選購比較合適。

本實例按用途分可選錢包(Wallet)和挎包(HandBag),按顏色分可選黃色(Yellow)和紅色(Red)??梢园磧蓚€維度定義為顏色類和包類。(點此下載本實例所要顯示的包的圖片)。

顏色類(Color)是一個維度,定義為實現化角色,它有兩個具體實現化角色:黃色和紅色,通過 getColor() 方法可以選擇顏色;包類(Bag)是另一個維度,定義為抽象化角色,它有兩個擴展抽象化角色:挎包和錢包,它包含了顏色類對象,通過 getName() 方法可以選擇相關顏色的挎包和錢包。

客戶類通過 ReadXML 類從 XML 配置文件中獲取包信息(點此下載 XML 配置文件),并把選到的產品通過窗體顯示出現,圖 2 所示是其結構圖。

女士皮包選購的結構圖
圖2 女士皮包選購的結構圖

程序代碼如下:
package bridge;
import java.awt.*;
import javax.swing.*;
public class BagManage
{
    public static void main(String[] args)
    {
        Color color;
        Bag bag;
        color=(Color)ReadXML.getObject("color");
        bag=(Bag)ReadXML.getObject("bag");
        bag.setColor(color);
        String name=bag.getName();
        show(name);
    }
    public static void show(String name)
    {
        JFrame jf=new JFrame("橋接模式測試");
        Container contentPane=jf.getContentPane();
        JPanel p=new JPanel();   
        JLabel l=new JLabel(new ImageIcon("src/bridge/"+name+".jpg"));
        p.setLayout(new GridLayout(1,1));
        p.setBorder(BorderFactory.createTitledBorder("女士皮包"));
        p.add(l);
        contentPane.add(p, BorderLayout.CENTER);
        jf.pack();  
        jf.setVisible(true);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}
//實現化角色:顏色
interface Color
{
    String getColor();
}
//具體實現化角色:黃色
class Yellow implements Color
{
    public String getColor()
    {
        return "yellow";
    }
}
//具體實現化角色:紅色
class Red implements Color
{
    public String getColor()
    {
        return "red";
    }
}
//抽象化角色:包
abstract class Bag
{
    protected Color color;
    public void setColor(Color color)
    {
        this.color=color;
    }   
    public abstract String getName();
}
//擴展抽象化角色:挎包
class HandBag extends Bag
{
    public String getName()
    {
        return color.getColor()+"HandBag";
    }   
}
//擴展抽象化角色:錢包
class Wallet extends Bag
{
    public String getName()
    {
        return color.getColor()+"Wallet";
    }   
}
package bridge;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;
class ReadXML
{
    public static Object getObject(String args)
    {
        try
        {
            DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();
            DocumentBuilder builder=dFactory.newDocumentBuilder();
            Document doc;                           
            doc=builder.parse(new File("src/bridge/config.xml"));
            NodeList nl=doc.getElementsByTagName("className");
            Node classNode=null;
            if(args.equals("color"))
            {
                classNode=nl.item(0).getFirstChild();
            }
            else if(args.equals("bag"))
            {
                classNode=nl.item(1).getFirstChild();
            }          
            String cName="bridge."+classNode.getNodeValue();
            Class<?> c=Class.forName(cName);
              Object obj=c.newInstance();
            return obj;
        }  
        catch(Exception e)
        {
               e.printStackTrace();
               return null;
        }
    }
}

程序的運行結果如圖 3 所示。

女士皮包選購的運行結果1
圖3 女士皮包選購的運行結果1

如果將 XML 配置文件按如下修改:
<?xml version="1.0" encoding="UTF-8"?>
<config>
    <className>Red</className>
    <className>Wallet</className>
</config>

則程序的運行結果如圖 4 所示。

女士皮包選購的運行結果2
圖4 女士皮包選購的運行結果2

橋接模式的應用場景

橋接模式通常適用于以下場景。
  1. 當一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展時。
  2. 當一個系統不希望使用繼承或因為多層次繼承導致系統類的個數急劇增加時。
  3. 當一個系統需要在構件的抽象化角色和具體化角色之間增加更多的靈活性時。

橋接模式模式的擴展

在軟件開發中,有時橋接(Bridge)模式可與適配器模式聯合使用。當橋接(Bridge)模式的實現化角色的接口與現有類的接口不一致時,可以在二者中間定義一個適配器將二者連接起來,其具體結構圖如圖 5 所示。

橋接模式與適配器模式聯用的結構圖
圖5 橋接模式與適配器模式聯用的結構圖
< 上一頁適配器模式 裝飾模式下一頁 >

精美而實用的網站,提供C語言、C++、STL、Linux、Shell、Java、Go語言等教程,以及socket、GCC、vi、Swing、設計模式、JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo