桥接模式
是什么(概念)
桥接模式(bridge pattern) 的定义是:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
桥接模式用一种巧妙的方式
处理多层继承存在的问题,用抽象关联来取代传统的多层继承,将类之间的静态继承关系转变为动态的组合关系
原理

桥接(Bridge)模式包含以下主要角色:
抽象化(Abstraction)角色 :主要负责定义出该角色的行为 ,并包含一个对实现化对象的引用。
扩展抽象化(RefinedAbstraction)角色 :是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
实现化(Implementor)角色 :定义实现化角色的接口,包含角色必须的行为和属性,并供扩展抽象化角色调用。
具体实现化(Concrete Implementor)角色 :给出实现化角色接口的具体实现。
桥接模式原理的核心是: 首先有要识别出一个类所
具有的的两个独立变化维度,将它们设计为两个独立的继承等级结构,为两个维度都提供抽象层,并建立抽象耦合。总结一句话就是:
抽象角色引用实现角色
应用实例
模拟不同的支付工具对应不同的支付模式,比如微信和支付宝都可以完成支付操作,而支付操作又可以有扫码支付、密码支付、人脸支付等,那么关于支付操作其实就有两个维度, 包括:支付渠道和支付方式

不使用设计模式
import org.junit.Test;
import java.math.BigDecimal;
/**
* @author mmdz
* @dec TODO 不使用设计模式 : 支付服务
*/
public class PayServer {
/**
* 支付
* @param uId 用户id
* @param tradeId 交易流水号
* @param amount 交易金额
* @param channelType 渠道类型 1 微信, 2 支付宝
* @param modeType 支付模式 1 密码,2 人脸,3 指纹
* @return
*/
public boolean doPay(String uId, String tradeId, BigDecimal amount, int channelType, int modeType){
if(1 == channelType){ // 微信支付
System.out.println("微信渠道支付划账开始......");
switch (modeType) {
case 1:
System.out.println("密码 支付……金额:" + amount);
break;
case 2:
System.out.println("人脸 支付……金额:" + amount);
break;
case 3:
System.out.println("指纹 支付……金额:" + amount);
break;
default:
System.out.println("错误 支付!!!");
break;
}
}
if(2 == channelType){ // 支付宝支付
System.out.println("支付宝渠道支付划账开始......");
switch (modeType) {
case 1:
System.out.println("密码 支付……金额:" + amount);
break;
case 2:
System.out.println("人脸 支付……金额:" + amount);
break;
case 3:
System.out.println("指纹 支付……金额:" + amount);
break;
default:
System.out.println("错误 支付!!!");
break;
}
}
return true;
}
@Test
public void TestPay(){
PayServer payServer = new PayServer();
System.out.println("测试: 微信支付、人脸支付方式");
payServer.doPay("wei xin_001","1000112333333",new BigDecimal(100),1,2);
System.out.println("\n测试: 支付宝支付、指纹支付方式");
payServer.doPay("zhi fu bao_002","1000112334567",new BigDecimal(100),2,3);
}
}
结果
测试: 微信支付、人脸支付方式 微信渠道支付划账开始...... 人脸 支付……金额:100 测试: 支付宝支付、指纹支付方式 支付宝渠道支付划账开始...... 指纹 支付……金额:100
从测试结果看,是满足了需求,但是这样的代码设计,后面的维护和扩展都会变得非常复杂
桥接模式重构代码
重构类图桥接模式原理的核心是: 首先有要识别出一个类所具有的的两个独立变化维度,将它们设计为两个独立的继承等级结构,为两个维度都提供抽象层,并建立抽象耦合。
Pay抽象类
支付渠道子类: 微信支付
支付渠道子类: 支付宝支付
IPayMode接口
支付模式实现: 刷脸支付
支付模式实现: 指纹支付
支付渠道*支付模式 = 相对应的组合

<!-- tabs:start -->
IPayMode
/**
* @author mmdz
* @dec TODO 接口 : 支付方式的具体实现
*/
public interface IPayMode {
/**
* 实际支付的方式 + 风控校验
* @return
*/
boolean security(String uid, BigDecimal amount);
}
// --------------------------------------------------------
/**
* @author mmdz
* @dec TODO 刷脸支付
*/
public class PayFaceMode implements IPayMode {
@Override
public boolean security(String uid, BigDecimal amount) {
System.out.println("根据用户ID,进行风控校验: 【余额充足】、【信誉良好】……");
System.out.println("刷脸 支付……金额:" + amount);
return true;
}
}
// --------------------------------------------------------
/**
* @author mmdz
* @dec TODO 密码支付
*/
public class PayPasswordMode implements IPayMode {
@Override
public boolean security(String uid, BigDecimal amount) {
System.out.println("根据用户ID,进行风控校验: 【余额充足】、【信誉良好】……");
System.out.println("密码 支付……金额:" + amount);
return true;
}
}
// --------------------------------------------------------
/**
* @author mmdz
* @dec TODO 指纹支付
*/
public class PayFingerMode implements IPayMode {
@Override
public boolean security(String uid, BigDecimal amount) {
System.out.println("根据用户ID,进行风控校验: 【余额充足】、【信誉良好】……");
System.out.println("指纹 支付……金额:" + amount);
return true;
}
}
Pay
/**
* @author mmdz
* @dec TODO 抽象类 : 支付 (渠道+方式)
*/
public abstract class Pay {
// 桥接对象
protected IPayMode payMode;
public Pay(IPayMode payMode) {
this.payMode = payMode;
}
// 划账功能
public abstract String transfer(String uId, String tradeId, BigDecimal amount);
}
// --------------------------------------------------------
/**
* @author mmdz
* @dec TODO 微信支付
*/
public class WxPay extends Pay {
public WxPay(IPayMode payMode) {
super(payMode);
}
@Override
public String transfer(String uId, String tradeId, BigDecimal amount) {
System.out.println("微信渠道支付划账开始......");
boolean security = payMode.security(uId, amount);
System.out.println("微信渠道支付风险校验: " + uId + " , " + tradeId +" , " + security);
if(!security){
System.out.println("微信渠道支付划账失败!");
return "500";
}
System.out.println("微信渠道划账成功!");
return "200";
}
}
// --------------------------------------------------------
/**
* @author mmdz
* @dec TODO 支付宝支付
*/
public class ZfbPay extends Pay {
public ZfbPay(IPayMode payMode) {
super(payMode);
}
@Override
public String transfer(String uId, String tradeId, BigDecimal amount) {
System.out.println("支付宝渠道支付划账开始......");
boolean security = payMode.security(uId, amount);
System.out.println("支付宝渠道支付风险校验: " + uId + " , " + tradeId +" , " + security);
if(!security){
System.out.println("支付宝渠道支付划账失败!");
return "500";
}
System.out.println("支付宝渠道划账成功!");
return "200";
}
}
测试&结果
public class TestPay {
@Test
public void testPay() {
System.out.println("测试场景1: 微信支付、人脸方式.");
Pay pay = new WxPay(new PayPasswordMode());
pay.transfer("wx_00100100", "10001900", new BigDecimal(100));
System.out.println("\n测试场景2: 支付宝支付、指纹方式");
Pay zfbPay = new ZfbPay(new PayFingerMode());
zfbPay.transfer("jlu1234567","567689999999",new BigDecimal(200));
}
}
结果
测试场景1: 微信支付、人脸方式. 微信渠道支付划账开始...... 根据用户ID,进行风控校验: 【余额充足】、【信誉良好】…… 密码 支付……金额:100 微信渠道支付风险校验: wx_00100100 , 10001900 , true 微信渠道划账成功! 测试场景2: 支付宝支付、指纹方式 支付宝渠道支付划账开始...... 根据用户ID,进行风控校验: 【余额充足】、【信誉良好】…… 指纹 支付……金额:200 支付宝渠道支付风险校验: jlu1234567 , 567689999999 , true 支付宝渠道划账成功!
<!-- tabs:end -->
代码重构完成后,结构更加清晰整洁, 可读性和易用性更高,外部的使用接口的用户不需要关心具体实现。桥接模式满足了单一职责原则和开闭原则,让每一部分都更加清晰并且易扩展。
总结
桥接模式的优点
分离抽象接口及其实现部分.桥接模式使用"对象间的关联关系"解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化.
在很多情况下,桥接模式可以取代多层继承方案.多层继承方案违背了单一职责原则,复用性差,类的个数多.桥接模式很好的解决了这些问题.
桥接模式提高了系统的扩展性,在两个变化维度中任意扩展一个维度都不需要修改原有系统,符合开闭原则.
桥接模式的缺点
桥接模式的使用会增加系统的理解和设计难度,由于关联关系建立在抽象层,要求开发者一开始就要对抽象层进行设计和编程
桥接模式要求正确识别出系统中的两个独立变化的维度,因此具有一定的局限性,并且如果正确的进行维度的划分,也需要相当丰富的经验.
桥接模式使用场景
需要提供平台独立性的应用程序时。 比如,不同数据库的 JDBC 驱动程序、硬盘驱动程序等。
需要在某种统一协议下增加更多组件时。 比如,在支付场景中,我们期望支持微信、支付宝、各大银行的支付组件等。这里的统一协议是收款、支付、扣款,而组件就是微信、支付宝等。
基于消息驱动的场景。 虽然消息的行为比较统一,主要包括发送、接收、处理和回执,但其实具体客户端的实现通常却各不相同,比如,手机短信、邮件消息、QQ 消息、微信消息等。
拆分复杂的类对象时。 当一个类中包含大量对象和方法时,既不方便阅读,也不方便修改。

浙公网安备 33010602011771号