赞
踩
桥接模式(bridge pattern) 的定义是:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联来取代传统的多层继承,将类之间的静态继承关系转变为动态的组合关系,使得系统更加灵活,并易于扩展,有效的控制了系统中类的个数 (避免了继承层次的指数级爆炸).
桥接(Bridge)模式包含以下主要角色:
桥接模式原理的核心是: 首先有要识别出一个类所具有的的两个独立变化维度,将它们设计为两个独立的继承等级结构,为两个维度都提供抽象层,并建立抽象耦合.总结一句话就是: 抽象角色引用实现角色
比如我们拿毛笔举例, 型号和颜色是毛笔的两个维度
模拟不同的支付工具对应不同的支付模式,比如微信和支付宝都可以完成支付操作,而支付操作又可以有扫码支付、密码支付、人脸支付等,那么关于支付操作其实就有两个维度, 包括:支付渠道和支付方式
不使用设计模式
public class PayController { /** * @param uId 用户id * @param tradeId 交易流水号 * @param amount 交易金额 * @param channelType 渠道类型 1 微信, 2 支付宝 * @param modeType 支付模式 1 密码,2 人脸,3 指纹 * @return: boolean */ public boolean doPay(String uId, String tradeId, BigDecimal amount,int channelType,int modeType){ //微信支付 if(1 == channelType){ System.out.println("微信渠道支付划账开始......"); if(1 == modeType){ System.out.println("密码支付"); }if(2 == modeType){ System.out.println("人脸支付"); }if(3 == modeType){ System.out.println("指纹支付"); } } //支付宝支付 if(2 == channelType){ System.out.println("支付宝渠道支付划账开始......"); if(1 == modeType){ System.out.println("密码支付"); }if(2 == modeType){ System.out.println("人脸支付"); }if(3 == modeType){ System.out.println("指纹支付"); } } return true; } } //测试 public class Test_Pay { public static void main(String[] args) { PayController payController = new PayController(); System.out.println("测试: 微信支付、人脸支付方式"); payController.doPay("weixin_001","1000112333333",new BigDecimal(100),1,2); System.out.println("\n测试: 支付宝支付、指纹支付方式"); payController.doPay("hifubao_002","1000112334567",new BigDecimal(100),2,3); } }
从测试结果看,是满足了需求,但是这样的代码设计,后面的维护和扩展都会变得非常复杂.
桥接模式重构代码
重构类图
桥接模式原理的核心是: 首先有要识别出一个类所具有的的两个独立变化维度,将它们设计为两个独立的继承等级结构,为两个维度都提供抽象层,并建立抽象耦合.
** 支付模式接口 (实现化角色)**
/**
* 支付模式接口
**/
public interface IPayMode {
//安全校验功能: 对各种支付模式进行风控校验
boolean security(String uId);
}
三种具体支付模式 (具体实现化角色)
//指纹支付及风控校验 public class PayFingerprintMode implements IPayMode { @Override public boolean security(String uId) { System.out.println("指纹支付,风控校验-指纹信息"); return true; } } //刷脸支付及风控校验 public class PayFaceMode implements IPayMode { @Override public boolean security(String uId) { System.out.println("人脸支付,风控校验-脸部识别"); return true; } } //密码支付及风控校验 public class PayCypher implements IPayMode { @Override public boolean security(String uId) { System.out.println("密码支付,风控校验-环境安全"); return false; } }
支付抽象类 (抽象化角色)
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 spikeCong * @date 2022/9/26 **/ 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); System.out.println("微信渠道支付风险校验: " + uId + " , " + tradeId +" , " + security); if(!security){ System.out.println("微信渠道支付划账失败!"); return "500"; } System.out.println("微信渠道划账成功! 金额: "+ amount); return "200"; } } /** * 支付渠道-支付宝划账 **/ 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); System.out.println("支付宝渠道支付风险校验: " + uId + " , " + tradeId +" , " + security); if(!security){ System.out.println("支付宝渠道支付划账失败!"); return "500"; } System.out.println("支付宝渠道划账成功! 金额: "+ amount); return "200"; } }
测试
@Test
public void test02() {
System.out.println("测试场景1: 微信支付、人脸方式.");
Pay wxpay = new WxPay(new PayFaceMode());
wxpay.transfer("wx_00100100","10001900",new BigDecimal(100));
System.out.println();
System.out.println("测试场景2: 支付宝支付、指纹方式");
Pay zfbPay = new ZfbPay(new PayFingerprintMode());
zfbPay.transfer("jlu1234567","567689999999",new BigDecimal(200));
}
代码重构完成后,结构更加清晰整洁, 可读性和易用性更高,外部的使用接口的用户不需要关心具体实现.桥接模式满足了单一职责原则和开闭原则,让每一部分都更加清晰并且易扩展.
桥接模式的优点:
桥接模式的缺点:
桥接模式使用场景
需要提供平台独立性的应用程序时。 比如,不同数据库的 JDBC 驱动程序、硬盘驱动程序等。
需要在某种统一协议下增加更多组件时。 比如,在支付场景中,我们期望支持微信、支付宝、各大银行的支付组件等。这里的统一协议是收款、支付、扣款,而组件就是微信、支付宝等。
基于消息驱动的场景。 虽然消息的行为比较统一,主要包括发送、接收、处理和回执,但其实具体客户端的实现通常却各不相同,比如,手机短信、邮件消息、QQ 消息、微信消息等。
拆分复杂的类对象时。 当一个类中包含大量对象和方法时,既不方便阅读,也不方便修改。
希望从多个独立维度上扩展时。 比如,系统功能性和非功能性角度,业务或技术角度等。
数据库驱动程序的设计:数据库驱动程序需要兼容不同的数据库系统,使用桥接模式可以将抽象的数据库操作与具体的数据库系统分离,使得可以方便地添加新的数据库系统支持。
消息发送器的设计:消息发送器需要支持不同的消息协议(例如邮件、短信、即时通信等),使用桥接模式可以将消息发送器与具体的消息协议分离,使得可以方便地添加新的消息协议支持。
音频播放器的设计:音频播放器需要兼容不同的音频格式,使用桥接模式可以将音频播放器的抽象部分与具体的音频格式分离,使得可以方便地添加新的音频格式支持。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。