桥接模式:
桥接模式(Bridge Pattern) 也称为桥梁模式、接口(Interface) 模式或柄体(Hand ie and Body) 模式,是将抽象部分与它的具体实现部分分离,使它们都可以独立地变化,属于结构型模式。
解耦轴象和实现,使得两者可以独立的变化。桥接模式主要目的是通过组合的方式建立两个类之间的联系,而不是继承。但又类似于多重继承方案,但是多重继承方案往往违背了类得单一职责原则,其复用性比较差,桥接模式是比多重继承更好的替代方案。桥接模式的核心在于解耦抽象和实现。
桥接模式主要包含四种角色:
- 抽象(Abstraction) :该类持有一个对实现角色的引用, 抽象角色中的方法需要实现角色来实现。抽象角色一般为抽象类(构造函数规定子类要传入一个实现对象);
- 修正抽象(Refined Abstraction) :Abstraction的具体实现, 对Abstraction的方法进行完善和扩展;
- 实现(Implementor) :确定实现维度的基本操作, 提供给Abstraction使用。该类一般为接口或抽象类;
- 具体实现(Concrete lm plement or) :Implementor的具体实现。
桥接模式的应用场景:
当一个类内部具备两种或多种变化维度时,使用桥接模式可以解耦这些变化的维度,使高层代码架构稳定。桥接模式适用于以下几种业务场景:
- 在抽象和具体实现之间需要增加更多的灵活性的场景。
- 一个类存在两个(或多个)独立变化的维度,而这两个(或多个)维度都需要独立进行扩展。
- 不希望使用继承,或因为多层继承导致系统类的个数剧增。
注:桥接模式的一个常用使用场景就是为了普接继承,我们知道,继承拥有很多优点,比如抽象,封装,多态等,父类封装共性,子类实现特性。继承可以展好地帮助我们实现代玛复用(封装)的功能,但是同时,这也是继承的一大缺点因为父类拥有的方法,子类也会继承得到,无论子类需不需要.这说明了继承具备强入侵性(父类代码侵入子类),同时会导致子类臃肿。因此,在设计模式中,有一个原则为:优先使用组合/聚合的方式,而不是继承。
在生活场景中的桥接模式也随处可见,比如连接起两个空间维度的桥,比如链接虚拟网络与真实网络的连接。
桥接模式在业务场景中的应用:
举个例子,我们平时办公的时候经常通过发邮件消息、短信消息或者系统内消息和同事进行沟通。尤其是在走一些审批流程的时候,我们需要记录这些过程以备查。我们根据消息的类别来划分的话,可以分为邮件消息、短信消息和系统内消息。但是,根据消息的紧急程度来划分的话,可以分为普通消息、紧急消息和特急消息。显然,整个消息体统可以划分为两个维度也就是我们上面提到的一个类存在两个(或多个)独立变化的维度,而这两个(或多个)维度都需要独立进行扩展。
首先创建一个IMessage 接口担任桥接的角色
public interface IMessage {
//发送消息的内容和接收人
void send(String message,String toUser);
}
创建邮件消息跟手机消息实现类:
public class EmailMessage implements IMessage {
public void send(String message, String toUser) {
System.out.println("使用邮件消息发送" + message + "给" + toUser);
}
}
public class SmsMessage implements IMessage {
public void send(String message, String toUser) {
System.out.println("使用短信消息发送" + message + "给" + toUser);
}
}
创建桥接抽象角色:
public abstract class AbastractMessage {
private IMessage message;
public AbastractMessage(IMessage message) {
this.message = message;
}
void sendMessage(String message, String toUser) {
this.message.send(message, toUser);
}
}
然后是普通消息及加急消息:
public class NomalMessage extends AbastractMessage {
public NomalMessage(IMessage message) {
super(message);
}
void sendMessage(String message, String toUser) {
message = "【普通】" + message;
super.sendMessage(message, toUser);
}
}
//--------------------------------------------
public class UrgencyMessage extends AbastractMessage {
public UrgencyMessage(IMessage message) {
super(message);
}
void sendMessage(String message, String toUser) {
message = "【加急】" + message;
super.sendMessage(message, toUser);
}
//根据messageId可以监控
public Object watch(String messageId) {
return null;
}
}
测试:
public class Test {
public static void main(String[] args) {
IMessage message = new SmsMessage();
AbastractMessage abastractMessage = new NomalMessage(message);
abastractMessage.sendMessage("加班申请", "王总");
message = new EmailMessage();
abastractMessage = new UrgencyMessage(message);
abastractMessage.sendMessage("加班申请", "王总");
}
}
通过上面的例子,我们能很好地感知到桥接模式造循了里氏替换,开闭原则,对修改关闭,对扩展开放。这里将桥接模式的优缺点总
优点:
- 分离抽象部分及其具体实
- 提高了系统的扩展性
- 符合开闭原则
- 符合合成复用原则
缺点:
- 增加了系统的理解与设计
- 需要正确地识别系统中两个独立变化的维度