桥模式-结构型

一、桥模式-结构型

1.1、核心思想

解耦抽象与实现,通俗一点就是将抽象部分与实现部分分离,使它们都可以独立变化

1.2、为什么会有桥模式?

在软件开发中,由于某些固有的实现逻辑,使得它们具有两个或者更多维度的变化,如果只是使用继承,会造成子类急剧增加,并且子类之间的代码重复性很高 ,桥模式就是为了解决这种问题。

以DNF--地下城与勇士为例,两个维度分别为职业武器

在没有使用桥模式之前

cpp 复制代码
// 角色基类
class Character
{
    public:
        virtual void attack() = 0;
        virtual void showInfo() = 0;
};

// 鬼泣 装备 太刀
class GhostCryWithTanto: public Character
{
    public:
        void attack() override
        {
            this->showInfo();
            std::cout << "使用技能:鬼斩!" << std::endl;
        }
        void showInfo() override
        {
            std::cout << "我是鬼剑士,职业是鬼泣,装备的是太刀" << std::endl;
        }
};

// 剑魂 装备 光剑
class SwordSoulWithLightSword: public Character
{
    public:
        void attack() override
        {
            this->showInfo();
            std::cout << "使用技能:里·鬼剑术!" << std::endl;
        }
        void showInfo() override
        {
            std::cout << "我是鬼剑士,职业是剑魂,装备的是光剑" << std::endl;
        }
};

// 狂战士 装备 巨剑
class BerserkerWithGreatSword: public Character
{
    public:
        void attack() override
        {
            this->showInfo();
            std::cout << "使用技能:崩山击!" << std::endl;
        }
        void showInfo() override
        {
            std::cout << "我是鬼剑士,职业是狂战士,装备的是巨剑" << std::endl;
        }
};

// 阿修罗 装备 短剑
class AsuraWithShortSword: public Character
{
    public:
        void attack() override
        {
            this->showInfo();
            std::cout << "使用技能:杀意波动!" << std::endl;
        }
        void showInfo() override
        {
            std::cout << "我是鬼剑士,职业是阿修罗,装备的是短剑" << std::endl;
        }
};

// 漫游 装备 左轮手枪
class WanderWithRevolver: public Character
{
    public:
        void attack() override
        {
            this->showInfo();
            std::cout << "使用技能:爆头一击!" << std::endl;
        }
        void showInfo() override
        {
            std::cout << "我是神枪手,职业是漫游,装备的是左轮手枪" << std::endl;
        }
};

// 枪炮师 装备 手炮
class GunslingerWithHandgun: public Character
{
    public:
        void attack() override
        {
            this->showInfo();
            std::cout << "使用技能:量子爆弹!" << std::endl;
        }
        void showInfo() override
        {
            std::cout << "我是神枪手,职业是枪炮师,装备的是手炮" << std::endl;
        }
};

// 机械师 装备 自动手枪
class MechanicWithPistol: public Character
{
    public:
        void attack() override
        {
            this->showInfo();
            std::cout << "使用技能:R-78追击者!" << std::endl;
        }
        void showInfo() override
        {
            std::cout << "我是神枪手,职业是机械师,装备的是自动手枪" << std::endl;
        }
};

// 弹药专家 装备 步枪
class BullpupWithRifle: public Character
{
    public:
        void attack() override
        {
            this->showInfo();
            std::cout << "使用技能:尼尔狙击!" << std::endl;
        }
        void showInfo() override
        {
            std::cout << "我是神枪手,职业是弹药专家,装备的是步枪" << std::endl;
        }
}

// 测试使用
void test1()
{
    std::cout<<"=== 不使用桥模式的DNF(职业 + 武器)==="<<std::endl;
    
    // 创建角色
    std::vector<Character*> characters;

    characters.push_back(new GhostCryWithTanto());
    characters.push_back(new SwordSoulWithLightSword());
    characters.push_back(new BerserkerWithGreatSword());
    characters.push_back(new AsuraWithShortSword());
    characters.push_back(new WanderWithRevolver());
    characters.push_back(new GunslingerWithHandgun());
    characters.push_back(new MechanicWithPistol());
    characters.push_back(new BullpupWithRifle());

    // 角色攻击
    for(const auto& character: characters)
    {
        character->attack();
    }

    for(const auto& character: characters){
        delete character;
    }
}
类数量进行分析:
基础职业 转职职业 武器 需要的类数量
鬼剑士 5个 太刀,光剑,巨剑,短剑,钝器 除剑魂能拿光剑,其余都不行; 16 + 5 = 21
神枪手 5个 左轮枪,手炮,步枪,手弩,自动手枪 25

问题所在

  1. 类爆炸:好家伙,目前就两个基础职业,就诞生了 21 + 25 = 46个类
  2. 维护成本高:比如修改其中一个职业(漫游)的攻击逻辑,需要修改5个类
  3. 无法动态切换武器:角色在战斗中无法更换武器
  4. 代码重复:相同的武器逻辑在不同职业中重复

使用桥模式之后

将武器进行抽象 + 职业进行抽象,变成两个维度

  • 武器部分进行抽象
c++ 复制代码
class Weapon
{
    public:
        virtual ~Weapon() = default;

        // 武器属性
        virtual std::string getName() const = 0;
        virtual int getPhysicalAttack() const = 0;
        virtual int getMagicalAttack() const = 0;
        virtual float getAttackSpeed() const = 0;
        virtual int getRequiredLevel() const = 0;

        virtual void specialEffect() const = 0;
        virtual std::string getSkillEnhancement() const = 0;

        virtual Weapon* clone() const = 0;
};

// 太刀
class Katana : public Weapon
{
private:
    std::string name;
    int level;

public:
    Katana(std::string name = "流光星陨刀", int level = 60)
        : name(name)
        , level(level)
    {
    }

    std::string getName() const override { return name; }
    int getPhysicalAttack() const override { return level * 15; }
    int getMagicalAttack() const override { return level * 25; }
    float getAttackSpeed() const override { return 1.2f; }
    int getRequiredLevel() const override { return level; }

    void specialEffect() const override
    {
        std::cout << "太刀特效:出血几率+30%,攻击时有一定的几率附加暗属性伤害\n";
    }

    std::string getSkillEnhancement()const override
    {
        return "技能[鬼斩]等级+3,[月光斩]等级+2";
    }

    Weapon* clone()const override
    {
        return new Katana(*this);
    }
};

// 光剑
class LightSword : public Weapon
{
private:
    std::string name;
    int level;

public:
    LightSword(std::string name = "赤光剑路易斯纳斯", int level = 90)
        : name(name)
        , level(level)
    {
    }

    std::string getName() const override { return name; }
    int getPhysicalAttack() const override { return level * 23; }
    int getMagicalAttack() const override { return level * 12; }
    float getAttackSpeed() const override { return 2.0f; }
    int getRequiredLevel() const override { return level; }

    void specialEffect() const override
    {
        std::cout << "光剑特效:感电几率+30%,攻击时有一定的几率附加光属性伤害\n";
    }

    std::string getSkillEnhancement()const override
    {
        return "技能[里·鬼剑术]等级+5,[破军升龙击]等级+2";
    }

    Weapon* clone()const override
    {
        return new LightSword(*this);
    }
};

// 短剑
class ShortSword : public Weapon
{
private:
    std::string name;
    int level;

public:
    ShortSword(std::string name = "无影剑-艾雷诺", int level = 70)
        : name(name), level(level) {
    }

    std::string getName() const override { return name; }
    int getPhysicalAttack() const override { return level * 12; }
    int getMagicalAttack() const override { return level * 23; }
    float getAttackSpeed() const override { return 0.8f; }
    int getRequiredLevel() const override { return level; }

    void specialEffect() const override {
        std::cout << "短剑特效:增加施放速度+5%, 物理/魔法暴击+2%" << std::endl;
    }

    std::string getSkillEnhancement() const override {
        return "技能[邪光斩]等级+3,[杀意波动]等级+2";
    }

    Weapon* clone() const override {
        return new ShortSword(*this);
    }
};

// 巨剑
class GreatSword : public Weapon
{
private:
    std::string name;
    int level;

public:
    GreatSword(std::string name = "魔剑-阿波菲斯", int level = 70)
        : name(name), level(level) {
    }

    std::string getName() const override { return name; }
    int getPhysicalAttack() const override { return level * 25; }
    int getMagicalAttack() const override { return level * 5; }
    float getAttackSpeed() const override { return 0.5f; }
    int getRequiredLevel() const override { return level; }

    void specialEffect() const override {
        std::cout << "巨剑特效:攻击时附加10%额外伤害" << std::endl;
    }

    std::string getSkillEnhancement() const override {
        return "技能[崩山裂地斩]等级+2,[血之狂暴]等级+1";
    }

    Weapon* clone() const override {
        return new GreatSword(*this);
    }
};

// 钝器
class BluntWeapon : public Weapon
{
private:
    std::string name;
    int level;

public:
    BluntWeapon(std::string name = "梁月的钝剑", int level = 85)
        : name(name), level(level) {
    }

    std::string getName() const override { return name; }
    int getPhysicalAttack() const override { return level * 23; }
    int getMagicalAttack() const override { return level * 2; }
    float getAttackSpeed() const override { return 0.5f; }
    int getRequiredLevel() const override { return level; }

    void specialEffect() const override {
        std::cout << "钝器特效:攻击时削减敌人25%防御力,每2秒叠加4%攻速、移速" << std::endl;
    }

    std::string getSkillEnhancement() const override {
        return "48级与85级技能等级+2";
    }

    Weapon* clone() const override {
        return new BluntWeapon(*this);
    }
};
  • 职业部分进行抽象
c++ 复制代码
class Character
{
protected:
    std::string name;
    int level;
    std::string career;
    Weapon* weapon;         // 桥模式的关键:持有武器的引用

public:
    Character(std::string _name, int _level, std::string _career)
        : name(_name)
        , level(_level)
        , career(_career)
        , weapon(nullptr)
    {
    }
    virtual ~Character()
    {
        if (weapon) {
            delete weapon;
            weapon = nullptr;
        }
    }

    // 装备武器(桥接的关键方法)
    void equipWeapon(Weapon* newWeapon) {
        if (newWeapon->getRequiredLevel() > level) {
            std::cout << "等级不足,无法装备 " << newWeapon->getName()
                << "(需要等级" << newWeapon->getRequiredLevel() << ")" << std::endl;
            return;
        }

        delete weapon;  // 卸下旧武器
        weapon = newWeapon->clone();  // 装备新武器(深拷贝)
        std::cout << name << " 装备了 " << weapon->getName() << std::endl;
    }

    // 卸下武器
    void unequipWeapon() {
        if (weapon) {
            std::cout << name << " 卸下了 " << weapon->getName() << std::endl;
            delete weapon;
            weapon = nullptr;
        }
    }

    // 攻击(具体职业实现)
    virtual void attack() const = 0;

    // 使用职业技能
    virtual void useSkill(std::string skillName) const = 0;

    // 显示角色信息
    virtual void showStatus() const {
        std::cout << "\n=== " << name << " ===" << std::endl;
        std::cout << "职业:" << career << "  Lv." << level << std::endl;

        if (weapon) {
            std::cout << "武器:" << weapon->getName()
                << "(物攻:" << weapon->getPhysicalAttack()
                << ",魔攻:" << weapon->getMagicalAttack()
                << ",攻速:" << weapon->getAttackSpeed() << ")" << std::endl;
            std::cout << "武器特效:";
            weapon->specialEffect();
            std::cout << "技能增强:" << weapon->getSkillEnhancement() << std::endl;
        }
        else {
            std::cout << "武器:无" << std::endl;
        }
    }

    // 计算总攻击力(职业特性 + 武器)
    virtual int getTotalPhysicalAttack() const {
        int baseAttack = level * 10;  // 基础攻击力
        return baseAttack + (weapon ? weapon->getPhysicalAttack() : 0);
    }

    virtual int getTotalMagicalAttack() const {
        int baseAttack = level * 8;  // 基础魔法攻击力
        return baseAttack + (weapon ? weapon->getMagicalAttack() : 0);
    }
};

class GhostSwordMan : public Character
{
public:
    GhostSwordMan(std::string name, int level)
        : Character(name, level, "鬼剑士") {
    }

    void attack() const override {
        if (weapon) {
            std::cout << name << " 使用 " << weapon->getName()
                << " 进行斩击!" << std::endl;
            std::cout << "   造成 " << getTotalPhysicalAttack() << " 点物理伤害" << std::endl;
        }
        else {
            std::cout << name << " 使用拳头攻击!" << std::endl;
        }
    }

    void useSkill(std::string skillName) const override {
        if (skillName == "鬼斩") {
            std::cout << name << " 释放鬼斩!" << std::endl;
            std::cout << "   造成 " << getTotalPhysicalAttack() * 2 << " 点暗属性伤害" << std::endl;
        }
        else if (skillName == "崩山击") {
            std::cout << name << " 使用崩山击!" << std::endl;
            std::cout << "   造成范围伤害,并击倒敌人" << std::endl;
        }
        else {
            std::cout << name << " 不会这个技能" << std::endl;
        }
    }
};

还可以再进一步细分五个转职职业:剑魂,狂战士,鬼泣,阿修罗,剑影;针对不同的职业,属性点不一样,专属技能也不同。

c++ 复制代码
void test2()
{
    std::cout << "====================桥模式====================" << std::endl;

    // 创建武器
    Katana* katana = new Katana("西岚的妖刀", 75);
    LightSword* lightSword = new LightSword("永恒星河", 65);
    ShortSword* shortSword = new ShortSword("巴恩的短剑", 90);
    GreatSword* greatSword = new GreatSword("神之意向", 100);
    BluntWeapon* bluntWeapon = new BluntWeapon("梁月的钝剑", 100);

    // 创建角色
    GhostSwordMan* ghostSwordMan = new GhostSwordMan("梁月", 90);

    // 装备武器
    std::cout << "---------装备武器---------\n";
    ghostSwordMan->equipWeapon(katana);

    // 使用技能
    std::cout << "---------使用技能---------\n";
    ghostSwordMan->useSkill("鬼斩");

    // 攻击
    std::cout << "---------攻击---------\n";
    ghostSwordMan->attack();

    // 显示状态
    std::cout << "---------显示状态---------\n";
    ghostSwordMan->showStatus();

    // 动态更换武器
    std::cout << "---------切换武器---------\n";
    ghostSwordMan->unequipWeapon();
    ghostSwordMan->equipWeapon(lightSword);

    // 再次显示状态
    std::cout << "---------再次显示状态---------\n";
    ghostSwordMan->showStatus();

    // clean
    delete ghostSwordMan;
    delete katana;
    delete lightSword;
    delete shortSword;
    delete greatSword;
    delete bluntWeapon;
}


可以明显看到:

特点 桥模式 不使用桥模式
类数量 相对较少 类数量较多
新增职业 只需要创建一个新职业类 需要为每个武器创建新类
新增武器 只需要创建一个新武器类 需要为每个职业创建新类
动态切换武器 可以 不能
扩展性
维护性

二、总结

2.1、优点:

  • 抽象和实现分离,增强系统扩展性:桥接模式将抽象部分与实现部分分离,使得它们可以独立变化。抽象部分和实现部分都可以独立扩展,而不需要修改其他部分。
  • 符合开闭原则:通过桥接模式,可以在不修改原有代码的情况下,增加新的抽象层和实现层,从而实现系统的扩展。
  • 符合合成复用原则:桥接模式通过将抽象部分和实现部分分离,使得抽象部分和实现部分可以独立变化,从而实现系统的复用。

2.2、缺点:

  • 增加了系统的理解与设计难度:桥接模式将抽象部分和实现部分分离,使得系统更加复杂,增加了系统的理解与设计难度。
  • 需要正确识别出系统中独立变化的维度:桥接模式要求正确识别出系统中独立变化的维度,否则可能会导致系统设计不合理,增加系统的复杂度。

2.3、使用场景:

  • 系统需要在抽象和实现之间增加更多的灵活性
  • 系统不希望使用继承导致系统类的个数急剧增加
  • 当存在多个独立变化的维度,且每个维度都有可能需要扩展时
相关推荐
连山齐名2 小时前
设计模式之一——堵塞队列
设计模式
D_evil__2 小时前
【Effective Modern C++】第三章 转向现代C++:9. 优先选用别名声明,而非typedef
c++
会员果汁2 小时前
19.设计模式-命令模式
设计模式·命令模式
HellowAmy2 小时前
我的C++规范 - 回调的设想
开发语言·c++·代码规范
茶本无香2 小时前
设计模式之六—组合模式:构建树形结构的艺术
java·设计模式·组合模式
安全二次方security²2 小时前
CUDA C++编程指南(7.1)——C++语言扩展之函数执行空间指定符
c++·人工智能·nvidia·cuda·cuda编程·global·函数执行空间指定符
Q741_1472 小时前
C++ 优先级队列 大小堆 模拟 力扣 1046. 最后一块石头的重量 每日一题
开发语言·c++·算法·leetcode·优先级队列·
KiefaC2 小时前
【C++】特殊类设计
开发语言·c++
坐怀不乱杯魂2 小时前
Linux - 进程信号
linux·c++