当然,这样的例子还有很多,如不同颜色和字体的笔墨、不同品牌和功率的汽车、不同性别和职业的男女、支持不同平台和不同文件格式的媒体播放器等。如果用桥接模式就能很好地办理这些问题。
桥接模式的定义与特点桥接(Bridge)模式的定义如下:将抽象与实现分离,使它们可以独立变革。它是用组合关系代替继续关系来实现,从而降落了抽象和实现这两个可变维度的耦合度。
通过上面的讲解,我们能很好的觉得到桥接模式遵照了里氏更换原则和依赖颠倒原则,终极实现了开闭原则,对修正关闭,对扩展开放。这里将桥接模式的优缺陷总结如下。
桥接(Bridge)模式的优点是:
抽象与实现分离,扩展能力强符合开闭原则符合合成复用原则实在现细节对客户透明缺陷是:由于聚合关系建立在抽象层,哀求开拓者针对抽象化进行设计与编程,能精确地识别出系统中两个独立变革的维度,这增加了系统的理解与设计难度。
桥接模式的构造与实现可以将抽象化部分与实现化部分分开,取消二者的继续关系,改用组合关系。
1. 模式的构造桥接(Bridge)模式包含以下紧张角色。
抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化工具的引用。扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。详细实现化(Concrete Implementor)角色:给出实现化角色接口的详细实现。其构造图如图 1 所示。
图1 桥接模式的构造图
2. 模式的实现桥接模式的代码如下:
package bridge;public class BridgeTest { public static void main(String[] args) { Implementor imple = new ConcreteImplementorA(); Abstraction abs = new RefinedAbstraction(imple); abs.Operation(); }}//实现化角色interface Implementor { public void OperationImpl();}//详细实现化角色class ConcreteImplementorA implements Implementor { public void OperationImpl() { System.out.println("详细实现化(Concrete Implementor)角色被访问"); }}//抽象化角色abstract class Abstraction { protected Implementor imple; protected Abstraction(Implementor imple) { this.imple = imple; } public abstract void Operation();}//扩展抽象化角色class RefinedAbstraction extends Abstraction { protected RefinedAbstraction(Implementor imple) { super(imple); } public void Operation() { System.out.println("扩展抽象化(Refined Abstraction)角色被访问"); imple.OperationImpl(); }}
程序的运行结果如下:
扩展抽象化(Refined Abstraction)角色被访问详细实现化(Concrete Implementor)角色被访问
桥接模式的运用实例
【例1】用桥接(Bridge)模式仿照女士皮包的选购。
剖析:女士皮包有很多种,可以按用场分、按皮质分、按品牌分、按颜色分、按大小分等,存在多个维度的变革,以是采取桥接模式来实现女士皮包的选购比较得当。
本实例按用场分可选钱包(Wallet)和挎包(HandBag),按颜色分可选黄色(Yellow)和赤色(Red)。可以按两个维度定义为颜色类和包类。
颜色类(Color)是一个维度,定义为实现化角色,它有两个详细实现化角色:黄色和赤色,通过 getColor() 方法可以选择颜色;包类(Bag)是另一个维度,定义为抽象化角色,它有两个扩展抽象化角色:挎包和钱包,它包含了颜色类工具,通过 getName() 方法可以选择干系颜色的挎包和钱包。
客户类通过 ReadXML 类从 XML 配置文件中获取包信息,并把选到的产品通过窗体显示涌现,图 2 所示是其构造图。
图2 女士皮包选购的构造图
程序代码如下:
package bridge;import org.w3c.dom.NodeList;import javax.swing.;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import java.awt.;public class BagManage { public static void main(String[] args) { Color color; Bag bag; color = (Color) ReadXML.getObject("color"); bag = (Bag) ReadXML.getObject("bag"); bag.setColor(color); String name = bag.getName(); show(name); } public static void show(String name) { JFrame jf = new JFrame("桥接模式测试"); Container contentPane = jf.getContentPane(); JPanel p = new JPanel(); JLabel l = new JLabel(new ImageIcon("src/bridge/" + name + ".jpg")); p.setLayout(new GridLayout(1, 1)); p.setBorder(BorderFactory.createTitledBorder("女士皮包")); p.add(l); contentPane.add(p, BorderLayout.CENTER); jf.pack(); jf.setVisible(true); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }}//实现化角色:颜色interface Color { String getColor();}//详细实现化角色:黄色class Yellow implements Color { public String getColor() { return "yellow"; }}//详细实现化角色:赤色class Red implements Color { public String getColor() { return "red"; }}//抽象化角色:包abstract class Bag { protected Color color; public void setColor(Color color) { this.color = color; } public abstract String getName();}//扩展抽象化角色:挎包class HandBag extends Bag { public String getName() { return color.getColor() + "HandBag"; }}//扩展抽象化角色:钱包class Wallet extends Bag { public String getName() { return color.getColor() + "Wallet"; }}package bridge; import javax.xml.parsers.; import org.w3c.dom.; import java.io.;class ReadXML { public static Object getObject(String args) { try { DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = dFactory.newDocumentBuilder(); Document doc; doc = builder.parse(new File("src/bridge/config.xml")); NodeList nl = doc.getElementsByTagName("className"); Node classNode = null; if (args.equals("color")) { classNode = nl.item(0).getFirstChild(); } else if (args.equals("bag")) { classNode = nl.item(1).getFirstChild(); } String cName = "bridge." + classNode.getNodeValue(); Class<?> c = Class.forName(cName); Object obj = c.newInstance(); return obj; } catch (Exception e) { e.printStackTrace(); return null; } }}
程序的运行结果如图 3 所示。
图3 女士皮包选购的运行结果1
如果将 XML 配置文件按如下修正:
<?xml version="1.0" encoding="UTF-8"?><config> <className>Red</className> <className>Wallet</className></config>
则程序的运行结果如图 4 所示。
图4 女士皮包选购的运行结果2
桥接模式的运用处景当一个类内部具备两种或多种变革维度时,利用桥接模式可以解耦这些变革的维度,使高层代码架构稳定。
桥接模式常日适用于以了局景。
当一个类存在两个独立变革的维度,且这两个维度都须要进行扩展时。当一个别系不肯望利用继续或由于多层次继续导致系统类的个数急剧增加时。当一个别系须要在构件的抽象化角色和详细化角色之间增加更多的灵巧性时。桥接模式的一个常见利用场景便是更换继续。我们知道,继续拥有很多优点,比如,抽象、封装、多态等,父类封装共性,子类实现特性。继续可以很好的实当代码复用(封装)的功能,但这也是继续的一大缺陷。
由于父类拥有的方法,子类也会继续得到,无论子类需不须要,这解释继续具备强侵入性(父类代码侵入子类),同时会导致子类臃肿。因此,在设计模式中,有一个原则为优先利用组合/聚合,而不是继续。
很多时候,我们分不清该利用继续还是组合/聚合或其他办法等,实在可以从现实语义进行思考。由于软件终极还是供应给现实生活中的人利用的,是做事于人类社会的,软件是具备现实场景的。当我们从纯代码角度无法看清问题时,现实角度可能会供应更加开阔的思路。
桥接模式模式的扩展在软件开拓中,有时桥接(Bridge)模式可与适配器模式联合利用。当桥接(Bridge)模式的实现化角色的接口与现有类的接口不一致时,可以在二者中间定义一个适配器将二者连接起来,其详细构造图如图 5 所示。
图5 桥接模式与适配器模式联用的构造图