C#桥接模式实战:解耦抽象与实现,消除重复代码

凌晨两点半
凌晨两点半
发布时间:2026-10-15 | 3人浏览过
原创

桥接模式是一种结构型设计模式,旨在将抽象部分与它的实现部分分离,使它们都可以独立地变化。在游戏开发或复杂业务逻辑中,当系统需要在两个或多个独立变化的维度上进行扩展时(例如“玩家类型”和“玩家行为”),直接使用继承会导致类爆炸。本文通过一个具体的C#实例,展示如何利用桥接模式解耦这些维度。

核心目标与原理

在传统的继承体系中,如果我们需要为多种玩家(如Player1, Player2)添加多种行为(如Move, Jump),通常的做法是创建子类来组合这些状态。然而,每当新增一种行为,就必须在每个玩家类中重复添加该方法,这违反了开闭原则并增加了维护成本。

桥接模式的核心思想是:使用对象间的组合关系代替继承关系。它将“抽象角色”(如玩家)与“实现角色”(如动作)分开定义。这样,我们可以任意组合不同的玩家类型和行为模式,而无需修改现有类的内部结构。

C# 桥接模式完整实例

下面是一个完整的C#控制台/Windows Forms混合示例,演示了如何构建这个解耦结构。代码分为四个关键部分:主程序入口、抽象行为、具体行为、以及抽象玩家和其具体子类。

第1步:定义实现部分的抽象接口(PlayAction)

首先,我们需要定义一个抽象基类,用于规范所有“动作”的行为。这一步确保了后续所有的具体动作都遵循统一的契约。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

// 意图(Intent):将抽象部分与实现部分分离,使它们都可以独立地变化。

namespace bridgepattern
{
    // 抽象部分:对实现部分进行抽象
    public abstract class playAction 
    {
        protected string actionstring;
        public string ActionString { get { return actionstring; } }
        
        // 定义抽象动作方法
        public abstract void action();
    }
}

第2步:提供具体的实现类(Move, Jump)

接下来,我们创建具体的动作类,它们继承自 playAction。这里展示了两种基本行为:移动和跳跃。如果需要新增“射击”或“防御”,只需再添加一个类,而无需改动任何玩家代码。

    // 实现玩家移动行为
    public class move : playAction
    {
        public override void action()
        {
            this.actionstring = "move";
        }
    }

    // 实现玩家跳跃行为
    public class jump : playAction
    {
        public override void action()
        {
            this.actionstring = "jump";
        }
    }
}

第3步:定义抽象部分及其客户端调用

这是桥接模式的关键类 bridge : Form。在这里,我们通过实例化具体的玩家和行为,并使用 setPlayAction 方法将它们绑定在一起,体现了“组合优于继承”的原则。

    public partial class bridge : Form
    {
        public bridge()
        {
            InitializeComponent();
        }

        private void btnDisplay_Click(object sender, EventArgs e)
        {
            // 组合1:玩家1 + 移动行为
            play p1 = new play1();
            p1.setPlayAction(new move()); // 注入具体行为
            p1.run(); // 执行
            this.listBox1.Items.Add(p1.playstring);

            // 组合2:玩家2 + 跳跃行为
            play p2 = new play2();
            p2.setPlayAction(new jump()); // 注入不同行为
            p2.run(); // 执行
            this.listBox1.Items.Add(p2.playstring);
        }
    }
}

第4步:实现抽象玩家基类与具体玩家

play 类作为抽象基类,持有一个 playAction 类型的引用。它定义了玩家的通用运行逻辑 run(),并在其中委托给具体的动作去执行。

    public abstract class play // 抽象部分
    {
        public string playstring { get; set; }
        protected playAction pa; // 持有实现部分的引用

        // 通过组合方式注入行为
        public void setPlayAction(playAction pa)
        {
            this.pa = pa;
        }

        // 抽象方法:由具体玩家类实现各自的标识
        public abstract void action();

        // 通用运行流程:先执行注入的动作,再执行自身的逻辑
        public void run()
        {
            if (pa != null) {
                pa.action(); // 执行实现部分(如设置move/jump字符串)
            }
            action(); // 执行抽象部分的变化
        }
    }

    // 具体玩家1
    public class play1 : play
    {
        public override void action()
        {
            // 拼接结果:玩家类型 + 当前行为描述
            if(pa != null)
                playstring = "play1" + pa.ActionString;
            else
                playstring = "play1";
        }
    }

    // 具体玩家2
    public class play2 : play
    {
        public override void action()
        {
            if(pa != null)
                playstring = "play2" + pa.ActionString;
            else
                playstring = "play2";
        }
    }

完成判断与应用场景

当你运行上述代码时,界面列表框中将显示 “play1move” 和 “play2jump”。这意味着:

  1. 独立性:如果我们新增一个 shoot 行为类,不需要修改 play, play1 或 play2 的任何代码。
  2. 灵活性:play1 可以在运行时动态切换行为,从 “move” 变为 “jump”。
  3. 解耦:抽象层级(玩家身份)与实现层级(动作功能)完全分离。

这种模式特别适用于那些既需要按“种类”划分,又需要按“行为/功能”划分的系统,如UI控件的主题与组件分离、数据库驱动层的封装等。

简要总结

桥接模式通过将二维度的继承关系转化为组合关系,极大地降低了系统的耦合度。在C#开发中,合理利用此类设计模式,能有效应对需求变更带来的代码重构压力。以上就是C#桥接模式用法的详细内容,更多关于C#设计模式的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表