文章目录
一、桥接模式简介
Bridge 模式又叫做桥接模式,是构造型的设计模式之一。Bridge模式基于类的最小设计原则,通过使用封装,聚合以及继承等行为来让不同的类承担不同的责任。它的主要特点是把抽象(abstraction)与行为实现(implementation)分离开来,从而可以保持各部分的独立性以及应对它们的功能扩展。
二、桥接模式的结构
三、桥接模式的角色与职责
- Client: Bridge模式的使用者
- Abstraction: 抽象类接口(接口或抽象类)维护对行为实现(Implementor)的引用
- Refined Abstraction: Abstraction子类
- Implementor: 行为实现类接口 (Abstraction接口定义了基于Implementor接口的更高层次的操作)
- ConcreteImplementor: Implementor子类
四、桥接模式的具体实现
现在有一家遥控器制造厂商和多家电视机制造商,每个电视机制造商的遥控器底层实现都不一样,并且在积极的更新换代,而遥控器制造商对于遥控器的制造也是精益求精,从原来的一大堆按键到极简形式的遥控器,各领风骚。
1、不使用桥接模式
方案设计
我们来看看这种一种无耻的方案。
类设计
首先是基本的电视机厂商实现接口:
// An highlighted block
package design.bridge.gys.nobridge;
public abstract class Control {
abstract void on();
abstract void off();
abstract void setChannel(int channel);
}
来看看Sony和LG厂商的底层实现:
// An highlighted block
package design.bridge.gys.nobridge;
public class SonyControl extends Control{
@Override
void on() {
// TODO Auto-generated method stub
System.out.println("Sony TV on");
}
@Override
void off() {
// TODO Auto-generated method stub
System.out.println("Sony TV off");
}
@Override
void setChannel(int channel) {
// TODO Auto-generated method stub
System.out.println("Channel :"+channel);
}
}
// An highlighted block
package design.bridge.gys.nobridge;
public class LGControl extends Control{
@Override
void on() {
// TODO Auto-generated method stub
System.out.println("LG TV on");
}
@Override
void off() {
// TODO Auto-generated method stub
System.out.println("LG TV off");
}
@Override
void setChannel(int channel) {
// TODO Auto-generated method stub
System.out.println("Channel :"+channel);
}
}
上面的是电视机厂商的底层,接下来的是遥控器厂商的一个设计形式:
// An highlighted block
package design.bridge.gys.nobridge;
public interface TVControl {
void OnOff();
void preChannel();
void nextChannel();
}
够简单的啊,音量键都没有。不管这个,看看给Sony和LG设计的遥控器吧。
Sony:
// An highlighted block
package design.bridge.gys.nobridge;
public class Sony extends SonyControl implements TVControl{
boolean state=false;
int channel=0;
@Override
public void OnOff() {
// TODO Auto-generated method stub
if(state==false)
{super.on();
state=true;}
else
{super.off();
state=false;}
}
@Override
public void preChannel() {
// TODO Auto-generated method stub
if(channel>0)
channel--;
else
channel=200;
super.setChannel(channel);
}
@Override
public void nextChannel() {
// TODO Auto-generated method stub
if(channel<200)
channel++;
else
channel=1;
super.setChannel(channel);
}
}
LG:
// An highlighted block
package design.bridge.gys.nobridge;
public class LG extends LGControl implements TVControl{
boolean state=false;
int channel=1;
@Override
public void OnOff() {
// TODO Auto-generated method stub
if(state==false)
{super.on();
state=true;}
else
{super.off();
state=false;}
}
@Override
public void preChannel() {
// TODO Auto-generated method stub
if(channel>1)
channel--;
else
channel=200;
super.setChannel(channel);
}
@Override
public void nextChannel() {
// TODO Auto-generated method stub
if(channel<199)
channel++;
else
channel=1;
super.setChannel(channel);
}
}
遥控器厂家的老板怕是要被两家老总打死。打开遥控器看电视吧:
// An highlighted block
package design.bridge.gys.nobridge;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Sony sc=new Sony();
LG lc=new LG();
sc.on();
sc.nextChannel();
sc.nextChannel();
sc.preChannel();
sc.off();
lc.on();
lc.preChannel();
lc.preChannel();
lc.off();
}
}
看看效果:
// An highlighted block
Sony TV on
Channel :1
Channel :2
Channel :1
Sony TV off
LG TV on
Channel :200
Channel :199
LG TV off
人模狗样还能运行起来哈。
这时候我们发现当遥控器厂商有n种类型遥控器时,再加上n个电视机制造商,我们需要n*n个遥控器类。实实在在的类爆炸啊。
2、使用桥接模式
好了,现在我们可以使用桥接模式来解决这个问题。
方案设计
类设计
和之前一样定义一个基本的电视接口,各个厂商均实现该接口,但是在底层有不同的实现。
现在遥控器厂商也做出了改变,技术主管做出了决定,设计一个接口,并且包含一个电视机厂商接口的域,以后每个遥控器新设计方案都继承这个接口:
// An highlighted block
package design.bridge.gys.bridge;
public abstract class Remote {
TV tv;
public Remote(TV tv) {
super();
this.tv = tv;
}
public abstract void onOff();
public abstract void preChannel();
public abstract void nextChnnel();
}
该抽象类中包含了一个域和三个抽象方法,以供子类实现。该设计方案一出,立马引起的关注,新一代遥控器出现了:
// An highlighted block
package design.bridge.gys.bridge;
public class RemoteControl1 extends Remote{
boolean state=false;
int channel=1;
public RemoteControl1(TV tv) {
super(tv);
// TODO Auto-generated constructor stub
}
@Override
public void onOff() {
// TODO Auto-generated method stub
if(state==false)
{tv.on();
state=true;}
else
{tv.off();
state=false;}
}
@Override
public void preChannel() {
// TODO Auto-generated method stub
if(channel>1)
channel--;
else
channel=200;
tv.setChannel(channel);
}
@Override
public void nextChnnel() {
// TODO Auto-generated method stub
if(channel<199)
channel++;
else
channel=1;
tv.setChannel(channel);
}
}
大功告成,是骡子是马拉出来溜溜啊。
// An highlighted block
package design.bridge.gys.bridge;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
RemoteControl1 ct1=new RemoteControl1(new SonyControl());
RemoteControl1 ct2=new RemoteControl1(new LGControl());
ct1.onOff();
ct1.preChannel();
ct1.nextChnnel();
ct1.nextChnnel();
ct1.onOff();
System.out.println("-----------");
ct2.onOff();
ct2.preChannel();
ct2.preChannel();
ct2.preChannel();
ct2.onOff();
}
}
看结果看结果:
// An highlighted block
Sony TV on
Channel :200
Channel :1
Channel :2
Sony TV off
-----------
LG TV on
Channel :200
Channel :199
Channel :198
LG TV off
很好,这次的复杂度没那么大了,代码也简单易懂。
掌声响起来。
其余的类:
// An highlighted block
package design.bridge.gys.bridge;
public interface TV {
void on();
void off();
void setChannel(int channel);
}
// An highlighted block
package design.bridge.gys.bridge;
public class LGControl implements TV{
@Override
public void on() {
// TODO Auto-generated method stub
System.out.println("LG TV on");
}
@Override
public void off() {
// TODO Auto-generated method stub
System.out.println("LG TV off");
}
@Override
public void setChannel(int channel) {
// TODO Auto-generated method stub
System.out.println("Channel :"+channel);
}
}
// An highlighted block
package design.bridge.gys.bridge;
public class SonyControl implements TV{
@Override
public void on() {
// TODO Auto-generated method stub
System.out.println("Sony TV on");
}
@Override
public void off() {
// TODO Auto-generated method stub
System.out.println("Sony TV off");
}
@Override
public void setChannel(int channel) {
// TODO Auto-generated method stub
System.out.println("Channel :"+channel);
}
}
五、桥接模式与策略模式的异同
- 桥接的目的让接口的实现和抽象可以分别演化,从而提高移植性;策略的目的是将复杂的算法进行封装,实现替换。
- 桥接是使用已有的方法或者类;策略为了扩展修改并提供动态配置。
- 桥接强调的是接口对象仅提供基本操作;策略的接口提供一种算法。