桥接模式介绍

发布时间:2024年01月16日

目录

一、桥接模式介绍

1.1 桥接模式定义

1.2 桥接模式原理

1.2.1 桥接模式类图

1.2.2 模式角色说明

1.2.3 举例说明

二、桥接模式的应用

2.1 需求说明

2.2 需求实现

2.2.1 不使用设计模式

2.2.2 使用桥接模式

2.2.2.1 类图

2.2.2.2 类图说明

2.2.2.3 具体实现(样例)

2.2.2.3.1 支付模式IPayMode接口 (实现化角色)

2.2.2.3.2 IPayMode接口实现

2.2.2.3.3 支付抽象类Pay

2.2.2.3.4 微信、支付宝支付实现类

2.2.2.3.5 测试类

三、桥接模式总结

3.1 桥接模式优点

3.2 桥接模式缺点

3.3 桥接模式使用场景


一、桥接模式介绍

1.1 桥接模式定义

桥接模式(bridge pattern) 的定义是:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联来取代传统的多层继承,将类之间的静态继承关系转变为动态的组合关系,使得系统更加灵活,并易于扩展,有效的控制了系统中类的个数 (避免了继承层次的指数级爆炸)。

1.2 桥接模式原理

1.2.1 桥接模式类图

1.2.2 模式角色说明

桥接(Bridge)模式包含以下主要角色:

  • 抽象化(Abstraction)角色 :主要负责定义出该角色的行为 ,并包含一个对实现化对象的引用。
  • 扩展抽象化(RefinedAbstraction)角色 :是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
  • 实现化(Implementor)角色 :定义实现化角色的接口,包含角色必须的行为和属性,并供扩展抽象化角色调用。
  • 具体实现化(Concrete Implementor)角色 :给出实现化角色接口的具体实现。

桥接模式原理的核心是:首先有要识别出一个类所具有的的两个独立变化维度,将它们设计为两个独立的继承等级结构,为两个维度都提供抽象层,并建立抽象耦合。总结一句话就是:抽象角色引用实现角色

1.2.3 举例说明

比如我们拿毛笔举例,型号和颜色是毛笔的两个维度型号是其固有的维度,所以抽象出一个毛笔类,而将各种型号的毛笔作为其子类,也就是下图的右侧抽象部分内容.颜色是毛笔的另一个维度,它与毛笔之间存在一种设置的关系,因此可以提供一个抽象的颜色接口,将具体颜色作为该接口的子类。

二、桥接模式的应用

2.1 需求说明

模拟不同的支付工具对应不同的支付模式,比如微信和支付宝都可以完成支付操作,而支付操作又可以有扫码支付、密码支付、人脸支付等,那么关于支付操作其实就有两个维度,包括:支付渠道和支付方式。

2.2 需求实现

2.2.1 不使用设计模式

package main.java.cn.test.bridge.V1;

import java.math.BigDecimal;

/**
 * @author ningzhaosheng
 * @date 2024/1/12 17:48:33
 * @description 不使用设计模式实现
 */
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;
    }
}

package main.java.cn.test.bridge.V1;

import java.math.BigDecimal;

/**
 * @author ningzhaosheng
 * @date 2024/1/12 17:50:07
 * @description 测试方法
 */
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);
    }
}

从测试结果看,是满足了需求,但是这样的代码设计,后面的维护和扩展都会变得非常复杂。

2.2.2 使用桥接模式

2.2.2.1 类图

2.2.2.2 类图说明

桥接模式原理的核心是:首先有要识别出一个类所具有的的两个独立变化维度,将它们设计为两个独立的继承等级结构,为两个维度都提供抽象层,并建立抽象耦合。

  • Pay抽象类

? 支付渠道子类: 微信支付
? 支付渠道子类: 支付宝支付

  • IPayMode接口

? 支付模式实现: 刷脸支付
? 支付模式实现: 指纹支付

  • 支付渠道*支付模式 = 相对应的组合.
2.2.2.3 具体实现(样例)
2.2.2.3.1 支付模式IPayMode接口 (实现化角色)
package main.java.cn.test.bridge.V2;

/**
 * @author ningzhaosheng
 * @date 2024/1/12 17:57:53
 * @description 支付模式接口
 */
public interface IPayMode {
    //安全校验功能: 对各种支付模式进行风控校验
    boolean security(String uId);
}

2.2.2.3.2 IPayMode接口实现
package main.java.cn.test.bridge.V2;

/**
 * @author ningzhaosheng
 * @date 2024/1/12 18:01:14
 * @description 密码支付及风控校验
 */
public class PayCypher implements IPayMode {
    @Override
    public boolean security(String uId) {
        System.out.println("密码支付,风控校验-环境安全");
        return false;
    }
}

package main.java.cn.test.bridge.V2;

/**
 * @author ningzhaosheng
 * @date 2024/1/12 18:00:30
 * @description 刷脸支付及风控校验
 */
public class PayFaceMode implements IPayMode {
    @Override
    public boolean security(String uId) {
        System.out.println("人脸支付,风控校验-脸部识别");
        return true;
    }
}

package main.java.cn.test.bridge.V2;

/**
 * @author ningzhaosheng
 * @date 2024/1/12 17:59:33
 * @description 指纹支付及风控校验
 */
public class PayFingerprintMode implements IPayMode {
    @Override
    public boolean security(String uId) {
        System.out.println("指纹支付,风控校验-指纹信息");
        return true;
    }
}

2.2.2.3.3 支付抽象类Pay
package main.java.cn.test.bridge.V2;

import java.math.BigDecimal;

/**
 * @author ningzhaosheng
 * @date 2024/1/12 18:02:02
 * @description 支付抽象类
 */
public abstract class Pay {
    //桥接对象
    protected IPayMode payMode;

    public Pay(IPayMode payMode) {
        this.payMode = payMode;
    }

    //划账功能
    public abstract String transfer(String uId, String
            tradeId, BigDecimal amount);
}

2.2.2.3.4 微信、支付宝支付实现类
package main.java.cn.test.bridge.V2;

import java.math.BigDecimal;

/**
 * @author ningzhaosheng
 * @date 2024/1/12 18:02:59
 * @description 支付渠道-微信划账
 */
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";
    }
}

package main.java.cn.test.bridge.V2;

import java.math.BigDecimal;

/**
 * @author ningzhaosheng
 * @date 2024/1/12 18:04:46
 * @description 支付渠道-支付宝划账
 */
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";

    }
}

2.2.2.3.5 测试类
package main.java.cn.test.bridge.V2;

import java.math.BigDecimal;

/**
 * @author ningzhaosheng
 * @date 2024/1/12 18:06:15
 * @description 测试
 */
public class Test_Pay {
    public static void main(String[] args) {
        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));
    }
}

代码重构完成后,结构更加清晰整洁,可读性和易用性更高,外部的使用接口的用户不需要关心具体实现。桥接模式满足了单一职责原则和开闭原则,让每一部分都更加清晰并且易扩展。

三、桥接模式总结

3.1 桥接模式优点

  1. 分离抽象接口及其实现部分。桥接模式使用"对象间的关联关系"解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。
  2. 在很多情况下,桥接模式可以取代多层继承方案。多层继承方案违背了单一职责原则,复用性差,类的个数多。桥接模式很好的解决了这些问题。
  3. 桥接模式提高了系统的扩展性,在两个变化维度中任意扩展一个维度都不需要修改原有系统,符合开闭原则。

3.2 桥接模式缺点

  1. 桥接模式的使用会增加系统的理解和设计难度,由于关联关系建立在抽象层,要求开发者一开始就要对抽象层进行设计和编程。
  2. 桥接模式要求正确识别出系统中的两个独立变化的维度,因此具有一定的局限性,并且如果正确的进行维度的划分,也需要相当丰富的经验。

3.3 桥接模式使用场景

  1. 需要提供平台独立性的应用程序时。 比如,不同数据库的 JDBC 驱动程序、硬盘驱动程序等。
  2. 需要在某种统一协议下增加更多组件时。 比如,在支付场景中,我们期望支持微信、支付宝、各大银行的支付组件等。这里的统一协议是收款、支付、扣款,而组件就是微信、支付宝等。
  3. 基于消息驱动的场景。 虽然消息的行为比较统一,主要包括发送、接收、处理和回执,但其实具体客户端的实现通常却各不相同,比如,手机短信、邮件消息、QQ 消息、微信消息等。
  4. 拆分复杂的类对象时。 当一个类中包含大量对象和方法时,既不方便阅读,也不方便修改。
  5. 希望从多个独立维度上扩展时。 比如,系统功能性和非功能性角度,业务或技术角度等。

好了,本次分享就到这里,欢迎大家继续阅读《设计模式》专栏其他设计模式内容,如果有帮助到大家,欢迎大家点赞+关注+收藏,有疑问也欢迎大家评论留言!

文章来源:https://blog.csdn.net/qq_25409421/article/details/135616880
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。