C#桥接模式实战:解耦抽象与实现,消除重复代码
桥接模式是一种结构型设计模式,旨在将抽象部分与它的实现部分分离,使它们都可以独立地变化。在游戏开发或复杂业务逻辑中,当系统需要在两个或多个独立变化的维度上进行扩展时(例如“玩家类型”和“玩家行为”),直接使用继承会导致类爆炸。本文通过一个具体的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”。这意味着:
- 独立性:如果我们新增一个
shoot行为类,不需要修改play,play1或play2的任何代码。 - 灵活性:
play1可以在运行时动态切换行为,从 “move” 变为 “jump”。 - 解耦:抽象层级(玩家身份)与实现层级(动作功能)完全分离。
这种模式特别适用于那些既需要按“种类”划分,又需要按“行为/功能”划分的系统,如UI控件的主题与组件分离、数据库驱动层的封装等。
简要总结
桥接模式通过将二维度的继承关系转化为组合关系,极大地降低了系统的耦合度。在C#开发中,合理利用此类设计模式,能有效应对需求变更带来的代码重构压力。以上就是C#桥接模式用法的详细内容,更多关于C#设计模式的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









