本文将与您一起了解桥接模式。模式定义将抽象与实现分开,允许它们独立变化。它通过用组合关系代替继承关系来实现,从而降低抽象和实现两个可变维度的耦合度。该模式实现如下:packagecom.niuh.designpattern.bridge.v1;/***bridgepattern*/publicclassBridgePattern{publicstaticvoidmain(String[]args){Implementorimple=newConcreteImplementorA();Abstractionabs=newRefinedAbstraction(imple);abs。Operation();}}//实现角色interfaceImplementor{voidOperationImpl();}//具体实现角色classConcreteImplementorAimplementsImplementor{publicvoidOperationImpl(){System.out.println("ConcreteImplementor角色被访问");}}//abstractclassAbstraction{protectedImplementorimple;protectedAbstraction(Implementorimple){this.imple=imple;}publicabstractvoidOperation();}//扩展抽象类RefinedAbstractionextendsAbstraction{protectedRefinedAbstraction(Implementorimple){super(imple);}public)voidOperation(.println("RefinedAbstraction角色被访问");imple.OperationImpl();}}输出结果如下:访问扩展抽象(RefinedAbstraction)角色,具体实现(ConcreteImplementor)角色被访问。有很多情况可能会发生变化,使用继承会造成类爆炸的问题,扩展起来也不灵活。模式组合可以将抽象部分和实现部分分开,取消两者之间的继承关系,改用组合关系。示例描述示例概述一家公司开发了一个财务管理系统,它有一个报表生成工具模块。客户可以指定任何类型的报表,如基本报表、交易报表、资金报表、资产报表等,并可以指定不同的报表样式,如饼图、直方图等。系统设计者设计了如下所示的类图下图为报告生成器的结构。后来在客户的使用过程中,客户想要添加一个新的报表,一个新的折线图。开发商这时候发现维护起来很麻烦。仔细分析后,设计者发现问题很严重,因为增加了新的报表或图表,需要添加很多子类。因此,系统分析人员最终根据面向对象的设计原则对上述方案重构了该模块,重构图如下所示。在这个重构方案中,报表和图形被设计成两个继承结构,两者都可以独立改变。编程时,可以只对抽象类进行编码,将具体的图形子类对象注入到具体的报表类中。这样,系统具有良好的扩展性和可维护性,符合面向对象设计原则的开闭原则。第一步:定义实现角色,报表接口interfaceIReport{voidoperationImpl();}第二步:定义实现角色(基础报表、交易报表、资金报表)classBasicReportimplementsIReport{@OverridepublicvoidoperationImpl(){System.out.println("基础报表被访问。”);}}classIntercourseReportimplementsIReport{@OverridepublicvoidoperationImpl(){System.out.println(“交易报告被访问。”);}}classCapitalReportimplementsIReport{@OverridepublicvoidoperationImpl(){System.out.println(“基金报告被访问");}}第三步:定义抽象角色,图abstractclassAbstractionGraph{protectedIReportiReport;publicAbstractionGraph(IReportiReport){this.iReport=iReport;}abstractvoidoperation();}第四步:定义扩展抽象作用(直方图、饼图)out.println("直方图被访问。");iReport.operationImpl();}}classPiechartextendsAbstractionGraph{publicPiechart(IReportiReport){super(iReport);}@Overridevoidoperation(){System.out.println("饼图被访问。");iReport.operationImpl();}}第五步:测试试试publicclassBridgePattern{publicstaticvoidmain(String[]args){//实现与抽象分离//基础报表IReportbasicReport=newBasicReport();//往来报表IReportintercourseReport=newIntercourseReport();//资金报表IReportcapitalReport=newCapitalReport();//基础报表使用直方图AbstractGraphbarchart=newBarchart(basicReport);barchart.operation();//基础报表使用饼图AbstractGraphiechart=newPiechart(basicReport);piechart.operation();}}访问输出结果直方图。访问的基本报告。访问饼图。访问基本报告。优点桥接模式遵循里氏替换原则和依赖倒置原则,最终实现了开闭原则,对修改关闭,对扩展开放。这里总结桥接模式的优缺点如下。Bridge模式的优点:抽象与实现分离,可扩展性强遵守开闭原则遵守复合复用原则实现细节对客户透明缺点由于在抽象层建立聚合关系,开发者要求设计和编程进行抽象,能够正确识别系统中两个独立变化的维度,增加了系统理解和设计的难度。应用场景当一个类有两个或多个变化维度时,可以使用桥接模式来解耦这些变化维度,稳定高层代码结构。桥接模式通常适用于以下场景:当一个类有两个独立变化的维度,两个维度都需要扩展;当一个系统不想使用继承或者系统类的数量由于多级继承而急剧增加时;当系统需要在组件的抽象角色和具体角色之间增加更多的灵活性时。桥接模式的一个常见用例是取代继承。我们知道继承有很多优点,比如抽象、封装、多态等,父类封装了共性,子类实现了特性。继承可以很好的实现代码复用(封装)的功能,但这也是继承的一大缺点。因为父类拥有的方法也会被子类继承,不管子类是否需要,这说明继承是侵入性很强的(父类的代码侵入子类),同时也会导致到臃肿的子类。因此,在设计模式中,有一个优先组合/聚合而不是继承的原则。桥接模式模式的扩展在软件开发中,有时桥接(Bridge)模式可以与适配器模式结合使用。当Bridge模式实现角色的接口与已有类的接口不一致时,可以在两者之间定义一个适配器来连接两者。结构图如下:源码中的应用JDBC驱动......DriverManager类DriverManager,作为一个抽象角色,聚合了已实现的角色Connection,但与标准桥接模式不同的是,DriverManager下没有子类班级。//WorkermethodcalledbythepublicgetConnection()methods.privatestaticConnectiongetConnection(Stringurl,java.util.Propertiesinfo,Class>caller)throwsSQLException{/**当callerCl为null时,我们应该检查应用程序的*(它是间接调用这个类)*类加载器,这样JDBC驱动类就可以从这里加载。*/ClassLoadercallerCL=caller!=null?caller.getClassLoader():null;synchronized(DriverManager.class){//同步加载正确的类加载器.if(callerCL==null){callerCL=Thread.currentThread().getContextClassLoader();}}if(url==null){thrownewSQLException("Theurlcannotbenull","08001");}println("DriverManager.getConnection(\""+url+"\")");//遍历尝试建立连接的已加载注册驱动程序。//记住引发的第一个异常,因此我们可以重新引发它。SQLExceptionreason=null;for(DriverInfoaDriver:registeredDrivers){//Ifthecallerdoesnothavepermissiontoloadthedriverthen//滑雪pit.if(isDriverAllowed(aDriver.driver,callerCL)){try{println("trying"+aDriver.driver.getClass().getName());Connectioncon=aDriver.driver.connect(url,info);if(con!=null){//成功!println("getConnectionreturning"+aDriver.driver.getClass().getName());return(con);}}catch(SQLExceptionex){if(reason==null){reason=ex;}}}else{println("skipping:"+aDriver.getClass().getName());}}//ifwegotherenobodycouldconnect.if(reason!=null){println("getConnectionfailed:"+reason);throwreason;}println("getConnection:nosuitabledriverfoundfor"+url);thrownewSQLException("Nosuitabledriverfoundfor"+url,"08001");}PS:以上代码提交在Github:https://github.com/Niuh-Study/niuh-设计模式.git
