软件设计模式学习(十一)桥接模式

桥接模式

桥接模式用一种很巧妙的方式处理继承存在的问题,用抽象关联取代了传统的多层继承,将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同时有效地控制了系统中类的个数。

模式动机 设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要四个形状类,如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有两种设计方案:第一种是为每一个行政都提供一套各种颜色的版本,这种方案使用的是多级继承结构,如果有四种形状,十二种颜色,则我们需要四十八个类。如果要增加新形状则同时也要具备所有的颜色,增加新的颜色也要为所有的形状添加对应颜色的子类;第二种提供四个形状类、十二种颜色类,根据实际对形状和颜色进行组合,此时系统中的类是十六个。如需增加新的形状或颜色,只需再增加一个新的形状类或颜色类即可。
很明显,对于有两个变化维度(即两个变化的原因)的系统,采用方案二可以使系统中类的个数更少,且系统扩展更为方便。

模式定义 将抽象部分与它的实现部分分离,使它们都可以独立地变化

模式结构 软件设计模式学习(十一)桥接模式
文章图片

桥接模式包含如下几个角色:
  1. Abstraction(抽象类)
    用于定义抽象类的接口,它一般是抽象类而不是接口,其中定义一个Implementor类型对象使其与implementor之间具有关联关系,它可以包含抽象的业务方法,还可以包含具体的业务方法。
  2. RefineAbstraction(扩充抽象类)
    扩充由Abstraction定义的接口,通常情况下是具体类,实现在Abstraction中定义的抽象业务方法,在RefineAbstraction可以调用Implementor中定义的业务方法。
  3. Implementor(实现类接口)
    对一些基本操作进行了定义,而具体实现交给其子类。
  4. ConcreteImplementorA(具体实现类)
    实现Implementor接口并且具体实现它,在不同的ConcreteImplementor中提供基本操作的不同实现,在程序运行时ConcreteImplementor对象将替换其父类对象,提供给客户具体的业务操作方法。

桥接模式实例之模拟毛笔
  1. 实例说明 现需提供大小两种型号的画笔,能绘制三种不同的颜色,只需五个类就能实现功能。
  2. 实例代码及解释
    1. 实现类接口Color
      public interface Color {void bepaint(String penType, String name); }

    2. 具体实现类Red
      public class Red implements Color {@Override public void bepaint(String penType, String name) { System.out.println(penType + "红色的" + name); } }

    3. 具体实现类Green
      public class Green implements Color {@Override public void bepaint(String penType, String name) { System.out.println(penType + "绿色的" + name); } }

    4. 具体实现类Blue
      public class Blue implements Color {@Override public void bepaint(String penType, String name) { System.out.println(penType + "蓝色的" + name); } }

    5. 抽象类Pen
      public abstract class Pen {protected Color color; public void setColor(Color color) { this.color = color; }public abstract void draw(String name); }

    6. 扩充抽象类BigPen
      public class BigPen extends Pen {@Override public void draw(String name) { String penType = "大号毛笔绘制"; this.color.bepaint(penType, name); } }

    7. 扩充抽象类SmallPen
      public class SmallPen extends Pen {@Override public void draw(String name) { String penType = "小号毛笔绘制"; this.color.bepaint(penType, name); } }

    8. 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; }} }

    9. 客户端测试类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("桃花"); } }

    10. 结果分析
      【软件设计模式学习(十一)桥接模式】如果在配置文件将第一个节点中内容设置为 Red,第一个节点中内容设置为 BigPen,则输出结果如下:
      软件设计模式学习(十一)桥接模式
      文章图片

      如果在配置文件将第一个节点中内容设置为 Blue,第一个节点中内容设置为 SmallPen,则输出结果如下:
      软件设计模式学习(十一)桥接模式
      文章图片

      如果需要增加新的毛笔或颜色,只需增加对应的扩充抽象类或具体实现类即可。在使用桥接模式设计的系统中,无论是哪个维度的扩展,对原有代码都无须修改,且更换具体类只需修改配置文件,桥接模式通过抽象方法耦合,使得系统具有良好的扩展能力。

    推荐阅读