07. 桥接模式(Bridge Pattern)
07. 桥接模式Bridge Pattern分类: 结构型模式热门度: ★★★☆☆难度: ★★★★☆ 概念桥接模式将抽象部分与实现部分分离使它们都可以独立变化。它通过组合替代继承解决了多层继承带来的类爆炸问题。桥接模式的核心思想是把形状和颜色分成两个独立的维度通过桥接组合连接而不是为每种形状×颜色的组合创建子类。 意图将抽象部分与实现部分分离使它们都可以独立变化。通过在抽象和实现之间建立桥接关系避免永久性的绑定关系提高系统的可扩展性。 关键角色角色说明抽象Abstraction定义抽象接口持有实现部分的引用扩展抽象Refined Abstraction扩展抽象接口通过桥接调用实现部分实现者Implementor定义实现部分的接口不必与抽象接口一致具体实现者Concrete Implementor实现实现者接口的具体类⚠️ 注意事项桥接模式是事前设计识别出系统中独立变化的维度与适配器模式不同适配器是事后补救桥接是预先设计两个维度的类数量从 M×N 降到 MN实现部分的接口应该足够通用不要包含抽象部分的逻辑适合多维度变化的场景如果只有一维变化则不需要桥接 实现流程客户端 → 创建具体实现者实例 → 创建扩展抽象注入实现者引用 → 调用扩展抽象的方法 → 扩展抽象通过桥接组合调用实现者的方法 → 两个维度独立变化互不影响 常见使用场景场景1: 图形绘制系统Drawing Shapes with Colors形状圆、矩形和颜色红、蓝是两个独立维度通过桥接避免 2×24 个子类。usingSystem;// 实现者接口 - 颜色publicinterfaceIColor{stringName{get;}voidApplyColor(stringshape);}// 具体实现者publicclassRedColor:IColor{publicstringName红色;publicvoidApplyColor(stringshape)Console.WriteLine($ 用红色绘制{shape});}publicclassBlueColor:IColor{publicstringName蓝色;publicvoidApplyColor(stringshape)Console.WriteLine($ 用蓝色绘制{shape});}publicclassGreenColor:IColor{publicstringName绿色;publicvoidApplyColor(stringshape)Console.WriteLine($ 用绿色绘制{shape});}// 抽象 - 形状publicabstractclassShape{protectedIColor_color;protectedShape(IColorcolor){_colorcolor;}publicabstractvoidDraw();}// 扩展抽象publicclassCircle:Shape{privatedouble_radius;publicCircle(IColorcolor,doubleradius):base(color){_radiusradius;}publicoverridevoidDraw(){Console.WriteLine($绘制圆形半径:{_radius});_color.ApplyColor(圆形);}}publicclassRectangle:Shape{privatedouble_width;privatedouble_height;publicRectangle(IColorcolor,doublewidth,doubleheight):base(color){_widthwidth;_heightheight;}publicoverridevoidDraw(){Console.WriteLine($绘制矩形{_width}x{_height});_color.ApplyColor(矩形);}}// 客户端调用publicclassProgram{publicstaticvoidMain(){varshapesnewShape[]{newCircle(newRedColor(),5),newRectangle(newBlueColor(),10,6),newCircle(newGreenColor(),3),newRectangle(newRedColor(),8,4)};foreach(varshapeinshapes){shape.Draw();Console.WriteLine();}}}场景2: 通知系统Notification System消息类型普通、紧急和发送渠道邮件、短信是两个独立维度。usingSystem;// 实现者接口 - 发送渠道publicinterfaceINotificationSender{stringChannelName{get;}voidSend(stringrecipient,stringsubject,stringbody);}// 具体实现者publicclassEmailSender:INotificationSender{publicstringChannelName邮件;publicvoidSend(stringrecipient,stringsubject,stringbody)Console.WriteLine($ [Email] To:{recipient}| Subject:{subject}\n Body:{body});}publicclassSmsSender:INotificationSender{publicstringChannelName短信;publicvoidSend(stringrecipient,stringsubject,stringbody)Console.WriteLine($ [SMS] To:{recipient}|{body});}publicclassPushSender:INotificationSender{publicstringChannelName推送;publicvoidSend(stringrecipient,stringsubject,stringbody)Console.WriteLine($ [Push] To:{recipient}| Title:{subject}|{body});}// 抽象 - 消息类型publicabstractclassNotification{protectedINotificationSender_sender;protectedNotification(INotificationSendersender){_sendersender;}publicabstractvoidSend(stringrecipient,stringtitle,stringcontent);}// 扩展抽象 - 普通通知publicclassNormalNotification:Notification{publicNormalNotification(INotificationSendersender):base(sender){}publicoverridevoidSend(stringrecipient,stringtitle,stringcontent){Console.WriteLine($[普通通知 -{_sender.ChannelName}]);_sender.Send(recipient,title,content);}}// 扩展抽象 - 紧急通知publicclassUrgentNotification:Notification{publicUrgentNotification(INotificationSendersender):base(sender){}publicoverridevoidSend(stringrecipient,stringtitle,stringcontent){Console.WriteLine($[紧急通知 -{_sender.ChannelName}] ⚠️);_sender.Send(recipient,$[紧急]{title},$【紧急】{content}\n请立即处理);}}// 扩展抽象 - 营销通知publicclassMarketingNotification:Notification{publicMarketingNotification(INotificationSendersender):base(sender){}publicoverridevoidSend(stringrecipient,stringtitle,stringcontent){Console.WriteLine($[营销通知 -{_sender.ChannelName}] );_sender.Send(recipient,title,${content}\n退订请回复TD);}}// 客户端调用publicclassProgram{publicstaticvoidMain(){// 3种渠道 × 3种类型 9种组合只需6个类而非9个Notification[]notifications{newNormalNotification(newEmailSender()),newUrgentNotification(newSmsSender()),newMarketingNotification(newPushSender()),newUrgentNotification(newEmailSender())};vartitlesnew[]{系统维护,服务器宕机,双十一特惠,安全告警};varcontentsnew[]{今晚22点维护,主服务器无响应,全场5折起,检测到异常登录};varrecipientsnew[]{usertest.com,13800138000,device_token_abc,admintest.com};for(inti0;inotifications.Length;i){notifications[i].Send(recipients[i],titles[i],contents[i]);Console.WriteLine();}}}场景3: 数据库驱动抽象Database Driver Abstraction数据库连接和命令是两个维度不同数据库SQL Server、MySQL支持不同的连接方式和命令语法。usingSystem;usingSystem.Collections.Generic;// 实现者接口 - 数据库驱动publicinterfaceIDatabaseDriver{stringDriverName{get;}stringBuildConnectionString(stringserver,stringdatabase);stringBuildQuery(stringtable,string[]columns,stringwhere);}// 具体实现者publicclassSqlServerDriver:IDatabaseDriver{publicstringDriverNameSQL Server;publicstringBuildConnectionString(stringserver,stringdatabase)$Server{server};Database{database};Integrated Securitytrue;TrustServerCertificatetrue;publicstringBuildQuery(stringtable,string[]columns,stringwhere)$SELECT [{string.Join(],[,columns)}] FROM [{table}](string.IsNullOrEmpty(where)?:$ WHERE{where});}publicclassMySqlDriver:IDatabaseDriver{publicstringDriverNameMySQL;publicstringBuildConnectionString(stringserver,stringdatabase)$Server{server};Database{database};Uidroot;Pwd;SslModePreferred;publicstringBuildQuery(stringtable,string[]columns,stringwhere)$SELECT {string.Join(,,columns)} FROM {table}(string.IsNullOrEmpty(where)?:$ WHERE{where});}publicclassPostgreSqlDriver:IDatabaseDriver{publicstringDriverNamePostgreSQL;publicstringBuildConnectionString(stringserver,stringdatabase)$Host{server};Database{database};Usernamepostgres;Password;publicstringBuildQuery(stringtable,string[]columns,stringwhere)$SELECT \{string.Join(\,\,columns)}\ FROM \{table}\(string.IsNullOrEmpty(where)?:$ WHERE{where});}// 抽象 - 数据库操作publicabstractclassDatabaseOperation{protectedIDatabaseDriver_driver;protectedDatabaseOperation(IDatabaseDriverdriver){_driverdriver;}publicabstractvoidConnect(stringserver,stringdatabase);publicabstractListDictionarystring,objectQuery(stringtable,string[]columns,stringwherenull);}// 扩展抽象 - 标准操作publicclassStandardDbOperation:DatabaseOperation{publicStandardDbOperation(IDatabaseDriverdriver):base(driver){}publicoverridevoidConnect(stringserver,stringdatabase){varconnStr_driver.BuildConnectionString(server,database);Console.WriteLine($[{_driver.DriverName}] 连接字符串:{connStr});Console.WriteLine($[{_driver.DriverName}] 已连接到{server}/{database});}publicoverrideListDictionarystring,objectQuery(stringtable,string[]columns,stringwherenull){varsql_driver.BuildQuery(table,columns,where);Console.WriteLine($[{_driver.DriverName}] 执行:{sql});// 模拟返回结果returnnewListDictionarystring,object{new(){[id]1,[name]张三},new(){[id]2,[name]李四}};}}// 客户端调用publicclassProgram{publicstaticvoidMain(){IDatabaseDriverdrivernewSqlServerDriver();vardbnewStandardDbOperation(driver);db.Connect(localhost,MyApp);varresultsdb.Query(Users,new[]{id,name},status active);Console.WriteLine($查询到{results.Count}条记录);foreach(varrowinresults)Console.WriteLine($ id{row[id]}, name{row[name]});}}✅ 优点分离抽象与实现两个维度可以独立扩展互不影响避免类爆炸从 M×N 个类减少到 MN 个类符合开闭原则新增形状或颜色都不需要修改已有代码符合单一职责原则每个类只负责一个维度的职责❌ 缺点增加理解难度需要识别系统中独立变化的维度增加了系统复杂度引入了更多的类和接口需要事前设计如果维度识别错误重构成本高 与其他模式对比模式区别适配器模式适配器是事后补救接口不兼容桥接是事前设计分离维度装饰器模式装饰器增强功能桥接分离抽象与实现策略模式策略关注算法替换桥接关注维度分离组合模式组合关注树形结构桥接关注多维度变化