Java设计模式之结构型模式-桥接模式(Bridge)

来源:互联网 发布:win7网络位置更改不了 编辑:程序博客网 时间:2024/05/22 14:14

  有关于面向对象的继承,我相信大家都已经能熟练的运用了,博主也不例外。在博主日常撸代码过程中,只要可以用继承的地方,我都会用上继承,因为它的功能确实强大!但是也有很多情况下,用继承也会带来麻烦。下面还是借桥接模式之手来阐述一下。

示例

  我这里用笔画画作为例子。
  比如说,我这里用不同的笔(圆珠笔、铅笔)绘制不同的形状。为了更加形象起见,我这里将不同的情况细化至具体类的方法。
  先来看下代码的结构图:
  
  下面来看下具体的实现过程:
  1. 创建抽象父类 Pen

public abstract class Pen {    private String name;    protected Pen(String name) {        this.name = name;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public abstract void draw();}

  2. 分别创建抽象子类 Pencil、BallPen继承抽象父类 Pen

public abstract class Pencil extends Pen {    protected Pencil() {        super("铅笔");    }}
public abstract class BallPen extends Pen {    protected BallPen() {        super("圆珠笔");    }}

  3. 对应的创建其具体的实现子类 CircleWithPencil、CircleWithBallPen、SquareWithPencil、SquareWithBallPen

public class CircleWithPencil extends Pencil {    @Override    public void draw() {        System.out.println(getName() + "画圆");    }}
public class CircleWithBallPen extends BallPen {    @Override    public void draw() {        System.out.println(getName() + "画圆");    }}
public class SquareWithPencil extends Pencil {    @Override    public void draw() {        System.out.println(getName() + "画正方形");    }}
public class SquareWithBallPen extends BallPen {    @Override    public void draw() {        System.out.println(getName() + "画正方形");    }}

  4. 测试类测试

public class Test {    public static void main(String[] args) {        Pen p;        p = new CircleWithBallPen();        p.draw();        p = new CircleWithPencil();        p.draw();        p = new SquareWithBallPen();        p.draw();        p = new SquareWithPencil();        p.draw();    }}

其运行结果如下:

圆珠笔画圆铅笔画圆圆珠笔画正方形铅笔画正方形

  上述代码一切看似很正常,没什么毛病对不对。但是你会发现一个问题,当我们需要扩展一项内容,比如说,用各种笔来绘制直线,那我们就需要在上方抽象子类 Pencil、BallPen中各自增加 LineWithPencil类和 LineWithBallPen类;或者说,我用彩笔来绘制各种图形,那我们需要新增一个抽象子类 ColourPen类, 然后写出其具体子类 CircleWithColourPen类和 SquareWithColourPen类。
  到这里也许你会疑问:这好像也没什么问题啊。
  的确,是没什么问题。如果我同时增加多种笔和多种形状,你会看到一个现象:我每增加一个笔的类型,在该笔的具体子类下你就得画出所有已经存在的形状;反之,每增加一种形状,在所有已经存在的笔的类型下你都要去实现这个形状的类。所以,其结果就会导致类成倍的增加。这种设计就使得程序代码变得相当臃肿,可见继承在这里给我们带来的麻烦。
  我们再来回顾上述的代码,在这里,变化的主要有两个部分,一个分部是笔,另外一个部分则是图形,针对这种多角度变化的问题,我们则使用桥接模式,来把这种多角度分离出来,让它们独立的变化,减少其之间的耦合。
  下面我们来看下桥接模式的做法。

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

实现过程

  我们对上述实例的代码做一些修改。
  先来看下修改后代码的结构图:
  
  下面来看下具体的代码:
  1. 创建抽象父类 Shape

public abstract class Shape {    public abstract String draw();}

  2. 创建Shape子类实现类 Circle、Square

public class Circle extends Shape {    @Override    public String draw() {        return "画圆";    }}
public class Square extends Shape {    @Override    public String draw() {        return "画正方形";    }}

  3. 创建抽象父类 Pen

public abstract class Pen {    private String name;    private Shape shape;    protected Pen(String name) {        this.name = name;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Shape getShape() {        return shape;    }    public void setShape(Shape shape) {        this.shape = shape;    }    protected String drawWhat() {        return shape.draw();    }    public abstract void draw();}

  4. 创建Pen子类实现类Pencil、BallPen

public class Pencil extends Pen {    public Pencil() {        super("铅笔");    }    @Override    public void draw() {        System.out.println(getName() + drawWhat());    }}
public class BallPen extends Pen {    public BallPen() {        super("圆珠笔");    }    @Override    public void draw() {        System.out.println(getName() + drawWhat());    }}

  5. 创建桥接测试类测试下

public class BridgeTest {    public static void main(String[] args) {        Pen p;        p = new BallPen();        p.setShape(new Circle());        p.draw();        p.setShape(new Square());        p.draw();        p = new Pencil();        p.setShape(new Circle());        p.draw();        p.setShape(new Square());        p.draw();    }}

运行的结果如下:

圆珠笔画圆圆珠笔画正方形铅笔画圆铅笔画正方形

四个要素

  1. Abstraction: 定义抽象类的接口。维护一个指向Implementor类型对象的指针。类似上述的Pen类。
  2. RefinedAbstraction: 扩充由Abstraction定义的接口。类似上述的Pencil、BallPen类。
  3. Implementor: 定义实现类的接口,该接口不一定要与Abstraction的接口完全的一致。类似上述的Shape类。
  4. ConcreteImplementor: 实现Implementor接口并定义它的具体实现。类似上述的Circle、Square类。

优点

   1. 抽象和实现的分离。
   2. 优秀的扩展能力。
   3. 实现细节对客户透明。
  桥接模式通过使用封装、聚合以及继承等行为来让不同的类承担起不同的责任,将抽象与行为的实现分离开来,保持各部分的独立性,以便其扩展。

其实桥接模式并不难,只是我自己写的有点啰嗦,还请各位多担待。

原创粉丝点击