原理或定義
把抽象部分和它的實現部分分離開來,讓兩者可獨立變化。這裏的抽象部分指的是一個概念層次上的東西,它的實現部分指的是實現這個東西的(功能)部分,分離就把實現部分從它要實現的抽象部分獨立出來,自我封裝成對象。
結構
抽象化(Abstraction)角色:抽象化給出的定義,並保存一個對實現化對象的引用。
修正抽象化(Refined Abstraction)角色:擴展抽象化角色,改變和修正父類對抽象化的定義。
實現化(Implementor)角色:這個角色給出實現化角色的接口,但不給出具體的實現。必須指出的是,這個接口不一定和抽象化角色的接口定義相同,實際上,這兩個接口可以非常不一樣。
具體實現化(Concrete Implementor)角色:這個角色給出實現接口的具體實現;
類圖
案例與代碼
本模式以遙控器項目來介紹
極簡設計方案:
public interface TvControl {
public void Onoff();
public void nextChannel();
public void preChannel();
}
class LGTvControl extends LGControl implements TvControl{
private static int ch=0;
private static boolean ison=false;
public void Onoff()
{
if(ison)
{
ison=false;
super.Off();
}else{
ison=true;
super.On();
}
}
public void nextChannel()
{
ch++;
super.setChannel(ch);
}
public void preChannel()
{
ch--;
if(ch<0)
{
ch=200;
}
super.setChannel(ch);
}
}
public class SonyTvControl extends SonyControl implements TvControl{
private static int ch=0;
private static boolean ison=false;
public void Onoff()
{
if(ison)
{
ison=false;
super.Off();
}else{
ison=true;
super.On();
}
}
public void nextChannel()
{
ch++;
super.setChannel(ch);
}
public void preChannel()
{
ch--;
if(ch<0)
{
ch=200;
}
super.setChannel(ch);
}
}
public class MainTest {
public static void main(String[] args) {
LGTvControl mLGTvControl=new LGTvControl();
SonyTvControl mSonyTvControl=new SonyTvControl();
mLGTvControl.Onoff();
mLGTvControl.nextChannel();
mLGTvControl.nextChannel();
mLGTvControl.preChannel();
mLGTvControl.Onoff();
mSonyTvControl.Onoff();
mSonyTvControl.preChannel();
mSonyTvControl.preChannel();
mSonyTvControl.preChannel();
mSonyTvControl.Onoff();
}
}
新需求:電視機廠家,遙控器新設計
這樣的設計方式每增加被遙控設備和遙控器改版都會帶來開發的不便。
橋接模式的設計方案:
類圖:
實現化(Implementor)角色:
public interface Control {
public void On();
public void Off();
public void setChannel(int ch);
public void setVolume(int vol);
}
public class LGControl implements Control {
@Override
public void On() {
// TODO Auto-generated method stub
System.out.println("**Open LG TV**");
}
@Override
public void Off() {
// TODO Auto-generated method stub
System.out.println("**Off LG TV**");
}
@Override
public void setChannel(int ch) {
// TODO Auto-generated method stub
System.out.println("**The LG TV Channel is setted "+ch+"**");
}
@Override
public void setVolume(int vol) {
// TODO Auto-generated method stub
System.out.println("**The LG TV Volume is setted "+vol+"**");
}
}
public class SharpControl implements Control {
@Override
public void On() {
// TODO Auto-generated method stub
System.out.println("***Open Sharp TV***");
}
@Override
public void Off() {
// TODO Auto-generated method stub
System.out.println("***Off Sharp TV***");
}
@Override
public void setChannel(int ch) {
// TODO Auto-generated method stub
System.out.println("***The Sharp TV Channel is setted "+ch+"***");
}
@Override
public void setVolume(int vol) {
// TODO Auto-generated method stub
System.out.println("***The Sharp TV Volume is setted "+vol+"***");
}
}
public class SonyControl implements Control {
@Override
public void On() {
// TODO Auto-generated method stub
System.out.println("*Open Sony TV*");
}
@Override
public void Off() {
// TODO Auto-generated method stub
System.out.println("*Off Sony TV*");
}
@Override
public void setChannel(int ch) {
// TODO Auto-generated method stub
System.out.println("*The Sony TV Channel is setted "+ch+"*");
}
@Override
public void setVolume(int vol) {
// TODO Auto-generated method stub
System.out.println("*The Sony TV Volume is setted "+vol+"*");
}
}
抽象化(Abstraction)角色:
public abstract class TvControlabs {
Control mControl=null;
public TvControlabs(Control mControl)
{
this.mControl=mControl;
}
public abstract void Onoff();
public abstract void nextChannel();
public abstract void preChannel();
}
修正抽象化(Refined Abstraction)角色:
public class TvControl extends TvControlabs {
private int ch=0;
private boolean ison=false;
public TvControl(Control mControl)
{
super(mControl);
}
@Override
public void Onoff() {
// TODO Auto-generated method stub
if(ison)
{
ison=false;
mControl.Off();
}else{
ison=true;
mControl.On();
}
}
@Override
public void nextChannel() {
// TODO Auto-generated method stub
ch++;
mControl.setChannel(ch);
}
@Override
public void preChannel() {
// TODO Auto-generated method stub
ch--;
if(ch<0)
{
ch=200;
}
mControl.setChannel(ch);
}
}
public class newTvControl extends TvControlabs {
private int ch=0;
private boolean ison=false;
private int prech=0;
public newTvControl(Control mControl) {
super(mControl);
// TODO Auto-generated constructor stub
}
@Override
public void Onoff() {
// TODO Auto-generated method stub
if(ison)
{
ison=false;
mControl.Off();
}else{
ison=true;
mControl.On();
}
}
@Override
public void nextChannel() {
// TODO Auto-generated method stub
prech=ch;
ch++;
mControl.setChannel(ch);
}
@Override
public void preChannel() {
// TODO Auto-generated method stub
prech=ch;
ch--;
if(ch<0)
{
ch=200;
}
mControl.setChannel(ch);
}
public void setChannel(int nch)
{
prech=ch;
ch=nch;
mControl.setChannel(ch);
}
public void Back()
{
mControl.setChannel(prech);
}
}
測試類:
public class MainTest {
public static void main(String[] args) {
TvControl mLGTvControl;
TvControl mSonyTvControl;
mSonyTvControl=new TvControl(new SonyControl());
mLGTvControl=new TvControl(new LGControl());
mLGTvControl.Onoff();
mLGTvControl.nextChannel();
mLGTvControl.nextChannel();
mLGTvControl.preChannel();
mLGTvControl.Onoff();
mSonyTvControl.Onoff();
mSonyTvControl.preChannel();
mSonyTvControl.preChannel();
mSonyTvControl.preChannel();
mSonyTvControl.Onoff();
newTvControl mSharpTvControl;
mSharpTvControl=new newTvControl(new SharpControl());
mSharpTvControl.Onoff();
mSharpTvControl.nextChannel();
mSharpTvControl.setChannel(9);
mSharpTvControl.setChannel(28);
mSharpTvControl.Back();
mSharpTvControl.Onoff();
}
}
將實現與抽象放在兩個不同的類層次中,使兩個層次可以獨立改變。
系統有多維角度分類時,而每一種分類又有可能變化,考慮使用橋接模式
橋接的目的是分離抽象與實現,使抽象和實現可以獨立變化。
使用場景
1、如果你不希望在抽象和實現部分採用固定的綁定關係,可以採用橋接模式,來把抽象和實現部分分開,然後在程序運行期間來動態的設置抽象部分需要用到的具體的實現,還可以動態切換具體的實現。
2、如果出現抽象部分和實現部分都應該可以擴展的情況,可以採用橋接模式,讓抽象部分和實現部分可以獨立的變化,從而可以靈活的進行單獨擴展,而不是攪在一起,擴展一邊會影響到另一邊。
3、如果希望實現部分的修改,不會對客戶產生影響,可以採用橋接模式,客戶是面向抽象的接口在運行,實現部分的修改,可以獨立於抽象部分,也就不會對客戶產生影響了,也可以說對客戶是透明的。
4、如果採用繼承的實現方案,會導致產生很多子類,對於這種情況,可以考慮採用橋接模式,分析功能變化的原因,看看是否能分離成不同的緯度,然後通過橋接模式來分離它們,從而減少子類的數目
優缺點
主要優點有:
1. 分離抽象部分和實現部分。
2. 更好的擴展性