概述:
所谓的桥接,是指中间有一座像桥一样的媒介,连接着桥两头的事物。从代码设计角度来讲,一般在拿到需求后,需要抽象出 变化的部分和固定的部分。在桥接模式中,“桥”连接的两头事物,属于变化的部分。两个变化的事物通过一座“桥”连接,进行了 解耦。
定义:
将抽象部分与它的实现部分分离,使它们都可以独立地变化
UML图:
桥接模式将抽象部分和实现部分进行分离,使它们可以独立地变化。
中间的聚合线,就是"桥"。
桥的左边 Abstraction: 抽象化角色,指忽略一些信息,把不同的实体当作同样的实体对待
桥的右边 Implementor:实现化角色,定义角色必需的行为和属性,与实现化是一对互逆的概念,实现化产生的对象比抽象化更具体,是对抽象化事物的进一步具体的产物
适用范围:
1、一个类可以有多个角度分类,每一种角度都可以进行扩展变化
2、如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,又想避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系
使用场景:
比如支付场景中,有微信支付、支付宝支付、银联支付等,支付方式有指纹、扫脸、密码支付。可以把微信、支付宝等支付看成是 抽象化角色(Abstraction),支付方式密码、指纹等看成是 实现化角色(Implementor)。
比如OA消息系统中,可以通过短信、邮件等方式进行消息发送,消息业务类型有 普通、紧急、特急类型。发送方式可以看成是 抽象化角色(Abstraction),消息业务类型可以看成是 实现化角色(Implementor)
以及Java应用的JDBC设计,其实也是桥接模式,uml图如下:
优缺点:
优点:
1、抽象和实现分离,使其可以各自变化
2、解决了多重继承带来的不灵活性
3、扩展能力增强
缺点:
1、增加对系统的理解和设计难度
举例:
有这样一个需求,通过短信、邮件发送消息,我们很自然的会创建如下的设计图:
此时增加一种紧急消息,UML图变成如下形式:
假设再增加一个 特急消息,UML图以此类推,会变成如下形式:
这里采用了多重继承的方式进行需求实现,扩展起来非常不方便。
其实在需求实现中我们可以发现,消息发送方式 短信、邮件这一维度是可以独自变化的,与具体消息类型可以区分开,这样再来一个需求,增加电话通知 这样的消息发送方式也没关系。
同样的消息业务类型,也是可以进行独立变化,普通、加急、特急、再加一个董事长紧急消息的需求 也没关系,照样可以灵活扩展。
下面我们用桥接模式画出UML图:
采用桥接模式后,结构变得清晰很多,并且灵活性也相应的提升了。
代码实现:
实现化角色:
/**
* 桥接模式-实现化角色
*/
public interface MessageImplementor {
void send(String msg, String to);
}
具体实现:
短信方式:
public class MessageSMS implements MessageImplementor {
@Override
public void send(String msg, String to) {
System.out.println("SMS:");
System.out.println("to: " + to);
System.out.println("content: " + msg);
}
}
邮件方式:
public class MessageMail implements MessageImplementor {
@Override
public void send(String msg, String to) {
System.out.println("Mail:");
System.out.println("to: " + to);
System.out.println("content: " + msg);
}
}
抽象化角色:
/**
* 消息抽象
*/
public abstract class AbstractMessage {
//消息实现
protected MessageImplementor messageImplementor;
public AbstractMessage() {
}
public void setMessageImplementor(MessageImplementor messageImplementor){
this.messageImplementor = messageImplementor;
}
public abstract void sendMsg(String msg, String to);
}
普通消息:
public class NormalMessage extends AbstractMessage{
@Override
public void sendMsg(String msg, String to) {
msg = "Normal-" + msg;
messageImplementor.send(msg, to);
}
}
加急消息:
public class UrgencyMessage extends AbstractMessage {
@Override
public void sendMsg(String msg, String to) {
msg = "Urgency!" + msg;
messageImplementor.send(msg, to);
}
}
特急消息:
public class SpecialUrgencyMessage extends AbstractMessage {
@Override
public void sendMsg(String msg, String to) {
msg = "Special Urgency!!" + msg;
messageImplementor.send(msg, to);
}
}
测试类:
public class BridgeTest {
public static void main(String[] args) {
//短信方式发送
MessageImplementor messageSMS = new MessageSMS();
//普通消息发送
AbstractMessage normalMessage = new NormalMessage();
normalMessage.setMessageImplementor(messageSMS);
normalMessage.sendMsg("请你吃饭", "13312341234");
//紧急消息发送
AbstractMessage urgencyMessage = new UrgencyMessage();
urgencyMessage.setMessageImplementor(messageSMS);
urgencyMessage.sendMsg("急着请你吃饭", "13312341234");
//特急消息发送
AbstractMessage specialUrgencyMessage = new SpecialUrgencyMessage();
specialUrgencyMessage.setMessageImplementor(messageSMS);
specialUrgencyMessage.sendMsg("非常迫切的想请你吃饭", "13312341234");
}
}
小结:
记住 桥接模式是 抽象和实现分离的概念就行