在嵌入式软件开发中,常常会遇到需要支持多个维度变化的场景。比如,在支付系统中,我们需要同时支持不同的 **支付渠道**(如微信支付、支付宝支付、银行卡支付等)和 **支付方式**(如密码支付、人脸支付、指纹支付等)。如果不加以合理设计,代码会变得非常复杂且不易扩展。为了应对这种需求,我们可以使用 桥接模式Bridge Pattern) 来进行解耦,提升系统的扩展性和可维护性。

本文将以 售卖饮料机的嵌入式支付系统 为例,讲解 桥接模式 的定义、应用场合,以及如何通过桥接模式实现灵活的支付渠道与支付方式的组合。我们还将展示不使用桥接模式和使用桥接模式时代码的变化,帮助您更好地理解这种模式的优势。

1. 什么是桥接模式?

1.1 桥接模式定义

桥接模式是一种 **结构型设计模式**,它通过将 抽象部分实现部分 分离,使得它们可以独立变化。桥接模式采用 组合 代替继承,避免了多层继承的复杂性,并为系统提供了更高的灵活性。

  • 抽象部分(Abstraction):定义了系统中的高层业务逻辑,并持有对实现部分的引用。

  • 实现部分(Implementor):定义了具体的功能实现接口,并由具体的实现类来完成。

通过桥接模式,我们可以让每个维度(例如支付渠道和支付方式)独立变化,从而避免代码复杂度的增加。

1.2 桥接模式的应用场合

桥接模式特别适用于以下场景:

  • 多维度变化的需求:当类的变化维度超过一个时,例如在支付系统中,支付渠道和支付方式是两个独立的变化维度。

  • 避免继承层次的膨胀:当多个变化维度通过继承实现时,会导致类的数量急剧增加,系统难以维护。

  • 系统需要高度扩展性:希望系统能够在不修改现有代码的基础上,轻松扩展新的功能和维度。

2. 不使用桥接模式的实现

2.1 需求

假设我们在一个售卖饮料的嵌入式系统中,需要实现支付功能。支付功能支持 微信支付 和 **支付宝支付**,支付方式包括 **密码支付**、**人脸支付** 和 **指纹支付**。如果不使用桥接模式,代码将会变得非常复杂,尤其是当我们需要增加新的支付渠道(例如银行卡支付)时。

2.2 不使用设计模式实现

#include <stdio.h>

int doPay(int channelType, int modeType)
{
    // 微信支付
    if (channelType == 1)
    {
        printf("微信支付开始...\n");
        if (modeType == 1)
        {
            printf("密码支付\n");
        }
        else if (modeType == 2)
        {
            printf("人脸支付\n");
        }
        else if (modeType == 3)
        {
            printf("指纹支付\n");
        }
    }
    // 支付宝支付
    else if (channelType == 2)
    {
        printf("支付宝支付开始...\n");
        if (modeType == 1)
        {
            printf("密码支付\n");
        }
        else if (modeType == 2)
        {
            printf("人脸支付\n");
        }
        else if (modeType == 3)
        {
            printf("指纹支付\n");
        }
    }
    return 0;
}

int main()
{
    // 测试:微信支付,人脸支付
    printf("测试:微信支付、人脸支付方式\n");
    doPay(1, 2);  // 微信支付 + 人脸支付
    
    // 测试:支付宝支付,指纹支付
    printf("\n测试:支付宝支付、指纹支付方式\n");
    doPay(2, 3);  // 支付宝支付 + 指纹支付
    
    return 0;
}

2.3 代码问题

  • 扩展性差:每新增一种支付方式或支付渠道,都需要修改 doPay 方法,违反了 **开闭原则**。

  • 代码冗长:随着支付渠道和支付方式的增加,if-else 语句会变得非常复杂,代码维护成本高。

2.4 新需求:添加银行卡支付

如果我们现在需要支持 **银行卡支付**,不使用桥接模式的实现会是这样的:

// 在原有基础上增加银行卡支付的判断
if (channelType == 3)
{
    printf("银行卡支付开始...\n");
    if (modeType == 1)
    {
        printf("密码支付\n");
    }
    else if (modeType == 2)
    {
        printf("人脸支付\n");
    }
    else if (modeType == 3)
    {
        printf("指纹支付\n");
    }
}

随着需求的增加,代码会变得更加庞大且不易维护,修改代码的地方也会更多。

3. 使用桥接模式的实现

3.1 需求

我们希望通过桥接模式来实现支付系统的灵活扩展,支持多种支付渠道和支付方式。通过将支付渠道和支付方式分离,我们可以方便地添加新的支付方式或支付渠道,而不需要修改现有代码。

3.2 使用桥接模式的设计

  • 支付模式接口(IPayMode):定义支付模式的接口。

  • 支付抽象类(Pay):定义支付渠道,并持有支付模式接口的引用。

  • 具体支付渠道(WxPay、ZfbPay、BankPay):实现具体的支付渠道。

  • 具体支付模式(PayCypher、PayFaceMode、PayFingerprintMode):实现不同的支付方式。

3.3 代码实现

3.3.1 支付模式接口 (IPayMode)
#include <stdio.h>
#include <stdbool.h>

typedef struct IPayMode IPayMode;

struct IPayMode
{
    bool (*security)(IPayMode *payMode, const char *uId);  // 安全校验方法
};

bool payCypherSecurity(IPayMode *payMode, const char *uId)
{
    printf("密码支付,风控校验:环境安全\n");
    return true;
}

bool payFaceModeSecurity(IPayMode *payMode, const char *uId)
{
    printf("人脸支付,风控校验:脸部识别\n");
    return true;
}

bool payFingerprintModeSecurity(IPayMode *payMode, const char *uId)
{
    printf("指纹支付,风控校验:指纹信息\n");
    return true;
}

IPayMode payCypher = {payCypherSecurity};
IPayMode payFaceMode = {payFaceModeSecurity};
IPayMode payFingerprintMode = {payFingerprintModeSecurity};
3.3.2 支付抽象类 (Pay)
#include <stdio.h>
#include <string.h>

typedef struct Pay Pay;
typedef struct IPayMode IPayMode;

struct Pay
{
    IPayMode *payMode;  // 支付模式接口
    const char *channel;      // 支付渠道
    void (*transfer)(Pay *pay, const char *uId, const char *tradeId, double amount);  // 划账功能
};

void wxPayTransfer(Pay *pay, const char *uId, const char *tradeId, double amount)
{
    printf("微信支付划账开始...\n");
    bool security = pay->payMode->security(pay->payMode, uId);
    printf("微信支付风险校验:%s,交易号:%s,安全性:%s\n", uId, tradeId, security ? "通过" : "失败");
    if (!security)
    {
        printf("微信支付划账失败!\n");
        return;
    }
    printf("微信支付划账成功!金额:%.2f\n", amount);
}

void zfbPayTransfer(Pay *pay, const char *uId, const char *tradeId, double amount)
{
    printf("支付宝支付划账开始...\n");
    bool security = pay->payMode->security(pay->payMode, uId);
    printf("支付宝支付风险校验:%s,交易号:%s,安全性:%s\n", uId, tradeId, security ? "通过" : "失败");
    if (!security)
    {
        printf("支付宝支付划账失败!\n");
        return;
    }


    printf("支付宝支付划账成功!金额:%.2f\n", amount);
}

void bankPayTransfer(Pay *pay, const char *uId, const char *tradeId, double amount)
{
    printf("银行卡支付划账开始...\n");
    bool security = pay->payMode->security(pay->payMode, uId);
    printf("银行卡支付风险校验:%s,交易号:%s,安全性:%s\n", uId, tradeId, security ? "通过" : "失败");
    if (!security)
    {
        printf("银行卡支付划账失败!\n");
        return;
    }
    printf("银行卡支付划账成功!金额:%.2f\n", amount);
}

void wxPayConstruct(Pay *pay, IPayMode *payMode)
{
    pay->payMode = payMode;
    pay->channel = "微信支付";
    pay->transfer = wxPayTransfer;
}

void zfbPayConstruct(Pay *pay, IPayMode *payMode)
{
    pay->payMode = payMode;
    pay->channel = "支付宝支付";
    pay->transfer = zfbPayTransfer;
}

void bankPayConstruct(Pay *pay, IPayMode *payMode)
{
    pay->payMode = payMode;
    pay->channel = "银行卡支付";
    pay->transfer = bankPayTransfer;
}
3.3.3 测试类
#include <stdio.h>

int main(void)
{
    Pay wxPay, zfbPay, bankPay;

    // 创建支付渠道
    wxPayConstruct(&wxPay, &payFaceMode);
    zfbPayConstruct(&zfbPay, &payFingerprintMode);
    bankPayConstruct(&bankPay, &payCypher);

    // 测试:微信支付,人脸支付
    printf("\n测试:微信支付,人脸支付\n");
    wxPay.transfer(&wxPay, "wx_00100100", "10001900", 100.0);

    // 测试:支付宝支付,指纹支付
    printf("\n测试:支付宝支付,指纹支付\n");
    zfbPay.transfer(&zfbPay, "zfb_1234567", "567689999999", 200.0);

    // 测试:银行卡支付,密码支付
    printf("\n测试:银行卡支付,密码支付\n");
    bankPay.transfer(&bankPay, "bank_1234567", "987654321", 300.0);

    return 0;
}

4. 优缺点比较

4.1 优点:
  • 耦合:通过桥接接口(IPayMode)将支付渠道和支付方式解耦,使得系统能够独立扩展新的支付方式和支付渠道。

  • 易于扩展:只需要新增一个支付渠道或支付方式,无需修改现有代码,符合 **开闭原则**。

  • 避免继承膨胀:通过组合替代继承,避免了继承层次过深,保持了代码的简洁和可维护性。

4.2 缺点:
  • 设计复杂:初期设计时需要识别出变化的维度并合理划分接口和类,可能会增加设计和理解的难度。

  • 可能会增加类的数量:桥接模式通过组合来替代继承,虽然避免了继承层次爆炸,但也会增加类的数量。

5. 总结

桥接模式特别适用于 **多维度变化的场景**,如支付系统中的支付渠道和支付方式的组合。在 售卖饮料机的嵌入式支付系统 中,桥接模式帮助我们将支付渠道(如微信支付、支付宝支付、银行卡支付)与支付方式(如密码支付、人脸支付、指纹支付)解耦,简化了代码的复杂度,使得系统更加灵活,易于扩展和维护。

通过本文的示例,您可以看到,桥接模式有效地解决了多个维度变化的组合问题,让系统能够在 不修改现有代码 的基础上,轻松扩展新的功能和维度。希望本文能够帮助您理解并在实际开发中运用 桥接模式 来提升代码质量和系统可扩展性。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐