桥接模式用一种很巧妙的方式处理继承存在的问题,用抽象关联取代了传统的多层继承,将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同时有效地控制了系统中类的个数。
模式动机
设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要四个形状类,如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有两种设计方案:第一种是为每一个行政都提供一套各种颜色的版本,这种方案使用的是多级继承结构,如果有四种形状,十二种颜色,则我们需要四十八个类。如果要增加新形状则同时也要具备所有的颜色,增加新的颜色也要为所有的形状添加对应颜色的子类;第二种提供四个形状类、十二种颜色类,根据实际对形状和颜色进行组合,此时系统中的类是十六个。如需增加新的形状或颜色,只需再增加一个新的形状类或颜色类即可。
很明显,对于有两个变化维度(即两个变化的原因)的系统,采用方案二可以使系统中类的个数更少,且系统扩展更为方便。
模式定义
将抽象部分与它的实现部分分离,使它们都可以独立地变化
模式结构
桥接模式包含如下几个角色:
-
Abstraction(抽象类)
用于定义抽象类的接口,它一般是抽象类而不是接口,其中定义一个Implementor类型对象使其与implementor之间具有关联关系,它可以包含抽象的业务方法,还可以包含具体的业务方法。
-
RefineAbstraction(扩充抽象类)
扩充由Abstraction定义的接口,通常情况下是具体类,实现在Abstraction中定义的抽象业务方法,在RefineAbstraction可以调用Implementor中定义的业务方法。
-
Implementor(实现类接口)
对一些基本操作进行了定义,而具体实现交给其子类。
-
ConcreteImplementorA(具体实现类)
实现Implementor接口并且具体实现它,在不同的ConcreteImplementor中提供基本操作的不同实现,在程序运行时ConcreteImplementor对象将替换其父类对象,提供给客户具体的业务操作方法。
桥接模式实例之模拟毛笔
-
实例说明
现需提供大小两种型号的画笔,能绘制三种不同的颜色,只需五个类就能实现功能。
-
实例代码及解释
-
实现类接口Color
public interface Color { void bepaint(String penType, String name); }
-
具体实现类Red
public class Red implements Color { @Override public void bepaint(String penType, String name) { System.out.println(penType + "红色的" + name); } }
-
具体实现类Green
public class Green implements Color { @Override public void bepaint(String penType, String name) { System.out.println(penType + "绿色的" + name); } }
-
具体实现类Blue
public class Blue implements Color { @Override public void bepaint(String penType, String name) { System.out.println(penType + "蓝色的" + name); } }
-
抽象类Pen
public abstract class Pen { protected Color color; public void setColor(Color color) { this.color = color; } public abstract void draw(String name); }
-
扩充抽象类BigPen
public class BigPen extends Pen { @Override public void draw(String name) { String penType = "大号毛笔绘制"; this.color.bepaint(penType, name); } }
-
扩充抽象类SmallPen
public class SmallPen extends Pen { @Override public void draw(String name) { String penType = "小号毛笔绘制"; this.color.bepaint(penType, name); } }
-
XML操作工具
public class XMLUtilPen { public static Object getBean(String args) { try { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); Document document = documentBuilder.parse(new File("configPen.xml")); NodeList nodeList = document.getElementsByTagName("className"); Node classNode = null; if (args.equals("color")) { classNode = nodeList.item(0).getFirstChild(); } else if (args.equals("pen")) { classNode = nodeList.item(1).getFirstChild(); } String cName = classNode.getNodeValue(); Class c = Class.forName("com.bridgePattern." + cName); Object o = c.newInstance(); return o; } catch (Exception e) { e.printStackTrace(); return null; } } }
-
客户端测试类Client
public class Client { public static void main(String[] args) { Color color = (Color) XMLUtilPen.getBean("color"); Pen pen = (Pen) XMLUtilPen.getBean("pen"); pen.setColor(color); pen.draw("桃花"); } }
-
结果分析
如果在配置文件将第一个节点中内容设置为 Red,第一个节点中内容设置为 BigPen,则输出结果如下:
如果在配置文件将第一个节点中内容设置为 Blue,第一个节点中内容设置为 SmallPen,则输出结果如下:
如果需要增加新的毛笔或颜色,只需增加对应的扩充抽象类或具体实现类即可。在使用桥接模式设计的系统中,无论是哪个维度的扩展,对原有代码都无须修改,且更换具体类只需修改配置文件,桥接模式通过抽象方法耦合,使得系统具有良好的扩展能力。
-