对于B/S架构来说我一直想结合实际开发环境来学习设计模式感觉这样印象会更加深起码你知道在什么场合下应用它之前也写过十多篇设计模式的文章之所以没有写完主要因为经验不够感觉不到其它设计模式在B/S架构中的应用场合和威力这篇我用桥接模式实现一个图书销售后计算最终售价的模块 假想案例说明出版社在出版的书后会在多家书店销售假如所有的书的销售都由一个总公司负责销售它可以控制书的销售方式例如计算机书打八折生活类的打七折等同时公司可以选择地区经销商做为二级代理二级代理都必须服从公司的促销方式如果公司打折二级代理也要打折否则二级代理不能私自打折同时总公司会根据二级代理的销售业绩分为不同的二级代理例如钻石黄金VIP等它们在得到的回扣上会有不同 需要的知识开-闭原则(OCP)以及组合/聚合复用原则(CARP)至于组合模式可以参考这篇文章老生常谈:组合模式 结构图这里我用图书销售价格计算模块来具体说明并不是标准图 桥接模式的定义【GOF】桥梁模式的用意是将抽象化(Abstraction)与实现化(Implementation)脱耦使得二者可以独立地变化这句话有三个关键词也就是抽象化实现化和脱耦 抽象化存在于多个实体中的共同的概念性联系就是抽象化作为一个过程抽象化就是忽略一些信息从而把不同的实体当做同样的实体对待【LISKOV】可以是接口也可以是抽象类用来定义一系列的操作定义 实现化抽象化给出的具体实现就是实现化也是平常说的具体类负责实现抽象类或者是接口定义的方法等 脱耦所谓耦合就是两个实体的行为的某种强关联而将它们的强关联去掉就是耦合的解脱或称脱耦在这里脱耦是指将抽象化和实现化之间的耦合解脱开或者说是将它们之间的强关联改换成弱关联将两个角色之间的继承关系改为聚合关系就是将它们之间的强关联改换成为弱关联因此桥梁模式中的所谓脱耦就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系从而使两者可以相对独立地变化可以看出这个系统含有两个等级结构也就是 )由抽象化角色和修正抽象化角色组成的抽象化等级结构 在结构图上由抽象化角色book修正抽象化角色lifebook和computerbook构成 )由实现化角色和两个具体实现化角色所组成的实现化等级结构在结构图上由diamondProxygoldProxyVIPProxy构成 桥梁模式所涉及的角色有这里为了看的清楚些我加上各部分的示例代码 :抽象化(Abstraction)角色抽象化给出的定义并保存一个对实现化对象的引用 abstractpublicclassbook { abstractpublicdoublepromotionPrice(); publicproxy_proxy; ///<summary> ///图书名称 ///</summary> publicstringbookName { get; set; } } :修正抽象化(Refined Abstraction)角色扩展抽象化角色改变和修正父类对抽象化的定义 publicclasscomputerBook:book { ///<summary> ///计算机图书打八折 ///</summary> ///<paramname=bookPrice>图书原价</param> ///<returns>经过图书正常打折以及代理商后的价格</returns> publicoverridedoublepromotionPrice() { //thrownewNotImplementedException(); bookPrice=bookPrice*; bookPrice=base_proxyproxyPrice(bookPrice); returnbookPrice; } ///<summary> ///图书价格 ///</summary> doublebookPrice; ///<summary> ///构造函数 ///</summary> ///<paramname=_bookPrice></param> publiccomputerBook(double_bookPrice) { thisbookPrice=_bookPrice; basebookName=C#入门经典; } } :实现化(Implementor)角色这个角色给出实现化角色的接口但不给出具体的实现必须指出的是这个接口不一定和抽象化角色的接口定义相同实际上这两个接口可以非常不一样实现化角色应当只给出底层操作而抽象化角色应当只给出基于底层操作的更高一层的操作 abstractpublicclassproxy { abstractpublicdoubleproxyPrice(doublepromotionPrice); ///<summary> ///代理商名称 ///</summary> publicstringproxyName { get; set; } ///<summary> ///代理商级别 ///</summary> publicstringproxyTye { get; set; } } :具体实现化(Concrete Implementor)角色这个角色给出实现化角色接口的具体实现 publicclassdiamondProxy:proxy { ///<summary> ///钻石级代理商的价格为图书正常打完折后的价格的八折 ///</summary> ///<paramname=promotionPrice></param> ///<returns></returns> publicoverridedoubleproxyPrice(doublepromotionPrice) { returnpromotionPrice*; } //decimalpromotionPrice; publicdiamondProxy() { baseproxyName=北京代理; baseproxyTye=钻石代理; } } 代码以及结构图分析可以看出在桥接模式中使用了组合模式如果不用组合模式呢当然也就不是桥接了下面的结构图是用继承实现的方案在结构图中有一个总的计算价格的接口IBook下面是两种打折方案的子类接IPromotionIProxy 使用继承的结构图如下 使用继承的代码如下 interfaceIBook { ///<summary> ///图书的价格接口 ///</summary> ///<returns></returns> doubleprice(); } interfaceIPromotion:IBook { ///<summary> ///图书正常打折后的价格接口 ///</summary> ///<returns></returns> doublepromotionPrice(); } interfaceIProxy:IBook { ///<summary> ///代理商打折后的价格接口 ///</summary> ///<returns></returns> doubleproxyPrice(); } publicclasscomputerBook:IPromotion { ///<summary> ///计算机图书打八折后的价格 ///</summary> ///<returns></returns> publicdoublepromotionPrice() { returnbookprice*; } doublebookprice; publiccomputerBook(double_bookprice) { thisbookprice=_bookprice; } ///<summary> ///返回打折后的图片价格 ///</summary> ///<returns></returns> publicdoubleprice() { returnthispromotionPrice(); } } publicclassdiamondProxy:IProxy { ///<summary> ///钻石代理商打八折后的价格 ///</summary> ///<returns></returns> publicdoubleproxyPrice() { returnbookprice*; } doublebookprice; publicdiamondProxy(double_bookprice) { thisbookprice=_bookprice; } ///<summary> ///返回打折后的图片价格 ///</summary> ///<returns></returns> publicdoubleprice() { returnthisproxyPrice(); } } 桥接与使用继承的比较 :在接口数量上来看桥接要少一个继承用了三个 从客户端调用程序来看可以看出桥接模式要简洁的多 ):使用桥接的客户端调用 //图书类型:计算机打折为八折 //原始价格:RMB //代理商级别钻石打折为八折 //计算最后实际等到的金额 book_Book=newcomputerBook(); _Book_proxy=newdiamondProxy(); doubleproxyPrice=_BookpromotionPrice(); ):使用继承的客户端调用 //实例化一本计算机图书 IBook_Book=newcomputerBook(); //得到计算机打完折后的价格 doubleprice=_Bookprice(); //实例化一位钻石代理商 IBook_BookProxy=newdiamondProxy(price); //把正常打折后的图片价格做为基数来计算最终价格 price=_BookProxyprice(); 从两者的业务逻辑代码来看显然是桥接模式精简不少起码在代码量上是这样 桥梁模式适用场合根据上面的分析在以下的情况下应当使用桥梁模式 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性避免在两个层次之间建立静态的联系 设计要求实现化角色的任何改变不应当影响客户端或者说实现化角色的改变对客户端是完全透明的 一个构件有多于一个的抽象化角色和实现化角色系统需要它们之间进行动态耦合 总结本文通过一个具体的书店销售图书中计算图书最终价格模块来说明桥接模式的应用系统可以轻松的在图书打折方式和代理商之间扩展及维护 |