设计模式之Bridge模式(桥接模式)

这几天重新去看spring系列的框架了(也又次体会到了理解设计模式在学习框架时的好处),没有接着写,发生了一些事,又少了些许束缚,但结果对向往自由的我来说总是好的,虎入山林,龙归沧海,听听音乐,整理整理博客。

书上的介绍比较简单,抽象,又看了一些其他东西才理解了一些。首先来介绍一下类的两个层次结构:功能层次结构和实现层次结构。
所谓功能层次结构,我们现在有一个类ActionSomething,想在它上面拓展新的功能,直接的方法就是继承他,添加一个派生类ActionSomethingGood,如果再想拓展功能会继续继承ActionSomethingGood,接着派生出ActionSomethingBetter,这样就是一个三层的功能层次结构,不过通常来说,类的层次结构不应过深。
在这里插入图片描述
然后是实现层次结构,模板方法模式中,我们了解了抽象类的强大之处,父类不但对子类规定了要实现的接口,还强制约束了这些接口的工作流程。父类的任务就是定义接口,而子类的任务就是实现这些抽象方法,这也是一种层次结构。例如,子类ConcreteClass实现了父类AbstractClass的抽象方法,构成了一个两层的实现结构:
在这里插入图片描述
但这个地方并非用来新增功能,而是为了实现新的任务分组,这就是类的实现层次结构,如果之后要以其他方式实现AbstractClass,只需再继承并实现类AnotherConcreteClass,类的层次结构发生了点变化:
在这里插入图片描述
我个人的简单理解就是功能层次结构就意味着功能的增加,而实现层次结构意味着功能的修改。
接下来是重点,也是桥接模式的主要优点:分离类的功能层次结构和实现层次结构。当然,如果只是简单的分离,两者之间必然缺少某种联系,因此还需要在二者之间搭起一个桥梁。书上说Bridge模式的作用就是搭建这座桥梁,但我个人的理解是如何分离类的两个层次结构也许更加重要。

说了不少,大伙可能还没理解,还是看一些代码更加容易理解,书上的例子我感觉可能还是有点抽象,因此我来写一个从别的地方看到的例子。
假如现在有一个生产各种笔的工厂,一开始规模较小,只生产铅笔和钢笔,笔的功能比较少,只有书写的功能,但不同笔在书写之前要做的操作是不一样的,我们可以得到以下的设计:
首先是一个抽象的笔类(此处使用了一点模板方法模式):

/**
 * @author lenovo
 * @title: AbstractPen
 * @projectName LearnDesignMode
 * @description: 抽象笔类
 * @date 2022/5/1523:18
 */
public abstract class AbstractPen {
    //笔在写之前要进行的操作  不同笔不一样,铅笔,钢笔等
    abstract void beforePrint();

    public void printSomething(String context) {
        beforePrint();
        System.out.println("写了" + context);
    }
}

接着我们来看铅笔和钢笔的实现类:

public class Pencil extends AbstractPen {
    @Override
    void beforePrint() {
        System.out.println("铅笔使用铅笔刀削好了");
    }
}
public class Pen extends AbstractPen {
    @Override
    void beforePrint() {
        System.out.println("钢笔拔下了笔帽,吸足了墨水");
    }
}

使用Main方法测试一下:

public class Main {
    public static void main(String[] args) {

        AbstractPen pen = new Pen();
        AbstractPen pencil = new Pencil();

        String context = "Hello,World";

        pen.printSomething(context);
        pencil.printSomething(context);
    }
}

输出结果:

钢笔拔下了笔帽,吸足了墨水
写了Hello,World
铅笔使用铅笔刀削好了
写了Hello,World

现在来看万事大吉,工厂在不断生产出笔来获取利润,慢慢的工厂做大,为卖出更多的笔,赚取更多利润,老板不再满足他的笔只有书写的功能,开始增加花里胡哨的功能,我们大可以直接由铅笔类和钢笔类进行派生进而增加新的功能,也遵守了开闭原则:

public class GoodPencil extends Pencil{
    public void newAbility() {
        System.out.println("第一个花里胡哨的功能");
    }
}
public class GoodPen extends Pen {
    public void newAbility() {
        System.out.println("第一个花里胡哨的功能");
    }
}

使用Main测试下:

public class Main {
    public static void main(String[] args) {

        GoodPen pen = new GoodPen();

        GoodPencil pencil = new GoodPencil();

        String context = "Hello,World";

        pen.printSomething(context);
        pen.newAbility();

        pencil.printSomething(context);
        pencil.newAbility();
    }
}

输出结果:

钢笔拔下了笔帽,吸足了墨水
写了Hello,World
第一个花里胡哨的功能
铅笔使用铅笔刀削好了
写了Hello,World
第一个花里胡哨的功能

好的,新增两个类之后,新的功能增加了,也没有破坏设计程序的开闭原则,看起来我们之前的设计好像是没有问题,有新的功能拓展起来非常棒。但老板仍不满足现状,又决定开始制造中性笔,新增一个中性笔类:

public class RollerBallPen extends AbstractPen {
    @Override
    void beforePrint() {
        System.out.println("中性笔拔下了笔帽");
    }

    public void newAbility() {
        System.out.println("第一个花里胡哨的功能");
    }
}

测试下并输出:

public class Main {
    public static void main(String[] args) {
        String context = "Hello,World";

        RollerBallPen rollerBallPen = new RollerBallPen();
        rollerBallPen.printSomething(context);
        rollerBallPen.newAbility();
    }
}
中性笔拔下了笔帽
写了Hello,World
第一个花里胡哨的功能

结果还不错,因为新增了一种笔,我们新增了一个类,还是达到了要求,但隐约感觉好像开始有问题了。果然,人的贪欲是无止境的。第二天,老板又要给所有的笔增加第二个花里胡哨的新功能。现在我们要怎么做,接着派生之前的三个类,增加新功能吗,类似下面的处理:

public class BetterPencil extends GoodPencil {
    public void secondNewAbility() {
        System.out.println("第二个花里胡哨的功能");
    }
}

要求肯定是可以达到的,可就因为一个小小功能的增加,我们要再增加三个类似的类来完成,如果后面再有新的笔呢,再来个马克笔,毛笔,水彩笔等等,到那时我们如果再新增一个新的功能会怎么样呢,类的个数是指数式增长的,想想就很恐怖。
造成如此的原因是什么,就是因为每种笔在使用之前的处理不同,这就是类的实现层次结构,新功能的添加呢,不就是类的功能层次结构吗,我们正可以通过桥接模式对这两种结构进行分离,来看改变之后的代码:
首先是AbstractPen,他不再是一个抽象类(主要因为在此处已没有要被子类实现的功能),并把之前的笔在使用之前的方法封装在了接口PenHandle中,在AbstractPen中引入即可:

public class AbstractPen {

    private PenHandle penHandle;

    public AbstractPen(PenHandle penHandle) {
        this.penHandle = penHandle;
    }

    public void printSomething(String context) {
        penHandle.beforePrint();
        System.out.println("写了" + context);
    }
}
public interface PenHandle {
    //使用前要进行的操作
    void beforePrint();
}

现在我们来实现三种笔的预处理:

public class PencilHandleImpl implements PenHandle {
    @Override
    public void beforePrint() {
        System.out.println("铅笔使用铅笔刀削好了");
    }
}
public class PenHandleImpl implements PenHandle {
    @Override
    public void beforePrint() {
        System.out.println("钢笔拔下了笔帽,吸足了墨水");
    }
}
public class RollerBallPenHandleImpl implements PenHandle {
    @Override
    public void beforePrint() {
        System.out.println("中性笔拔下了笔帽");
    }
}

那要如何生产三种笔呢,直接看Main方法:

public class Main {
    public static void main(String[] args) {

        String context = "Hello,World";

        PenHandle pen = new PenHandleImpl();
        PenHandle pencil = new PencilHandleImpl();
        PenHandle rollerBallPen = new RollerBallPenHandleImpl();

        AbstractPen concretePen = new AbstractPen(pen);
        AbstractPen concretePencil = new AbstractPen(pencil);
        AbstractPen concreteRollerBallPen = new AbstractPen(rollerBallPen);

        concretePen.printSomething(context);
        concretePencil.printSomething(context);
        concreteRollerBallPen.printSomething(context);

    }
}

来看结果:

钢笔拔下了笔帽,吸足了墨水
写了Hello,World
铅笔使用铅笔刀削好了
写了Hello,World
中性笔拔下了笔帽
写了Hello,World

非常好的完成了任务,那要新增功能呢,只需继承AbstractPen并拓展即可:

public class GoodPen extends AbstractPen {
    public GoodPen(PenHandle penHandle) {
        super(penHandle);
    }

    public void newAbility() {
        System.out.println("第一个花里胡哨的功能");
    }
}

测试一下并输出:

public class Main {
    public static void main(String[] args) {

        String context = "Hello,World";

        PenHandle pen = new PenHandleImpl();
        PenHandle pencil = new PencilHandleImpl();
        PenHandle rollerBallPen = new RollerBallPenHandleImpl();

        GoodPen concretePen = new GoodPen(pen);
        GoodPen concretePencil = new GoodPen(pencil);
        GoodPen concreteRollerBallPen = new GoodPen(rollerBallPen);

        concretePen.printSomething(context);
        concretePen.newAbility();
        concretePencil.printSomething(context);
        concretePencil.newAbility();
        concreteRollerBallPen.printSomething(context);
        concreteRollerBallPen.newAbility();

    }
}
钢笔拔下了笔帽,吸足了墨水
写了Hello,World
第一个花里胡哨的功能
铅笔使用铅笔刀削好了
写了Hello,World
第一个花里胡哨的功能
中性笔拔下了笔帽
写了Hello,World
第一个花里胡哨的功能

如果还有新的功能呢,依旧是继承,然后派生即可,而不是有多少种笔就新增多少类,那是非常糟糕的处理。
此时我们就实现了类的功能层次结构(新增功能)和实现层次结构(修改功能)的分离,以上我个人对桥接模式的一些理解。

这篇文章可以说是我写的比较认真的,写的时间也比较长,希望看到这里的各位点赞支持一下,大家一起进步。

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
桥接模式是一种结构型设计模式,它的主要目的是将抽象部分与实现部分分离,使它们能够独立地变化。下面是一个Java桥接模式的示例: 首先定义一个抽象类Shape,它有一个DrawAPI的成员变量,表示它的实现。 ```java public abstract class Shape { protected DrawAPI drawAPI; protected Shape(DrawAPI drawAPI) { this.drawAPI = drawAPI; } public abstract void draw(); } ``` 然后定义具体的形状类,比如Circle和Rectangle,它们继承自抽象类Shape,并实现了draw方法。 ```java public class Circle extends Shape { private int x, y, radius; public Circle(int x, int y, int radius, DrawAPI drawAPI) { super(drawAPI); this.x = x; this.y = y; this.radius = radius; } @Override public void draw() { drawAPI.drawCircle(radius, x, y); } } public class Rectangle extends Shape { private int x, y, width, height; public Rectangle(int x, int y, int width, int height, DrawAPI drawAPI) { super(drawAPI); this.x = x; this.y = y; this.width = width; this.height = height; } @Override public void draw() { drawAPI.drawRectangle(x, y, width, height); } } ``` 最后定义一个DrawAPI接口,它有两个方法drawCircle和drawRectangle,表示画圆和画矩形的实现。 ```java public interface DrawAPI { void drawCircle(int radius, int x, int y); void drawRectangle(int x, int y, int width, int height); } ``` 现在,我们可以使用不同的DrawAPI实现来创建不同的Shape对象,比如: ```java DrawAPI redDrawAPI = new RedDrawAPI(); Shape redCircle = new Circle(100, 100, 10, redDrawAPI); redCircle.draw(); DrawAPI greenDrawAPI = new GreenDrawAPI(); Shape greenRectangle = new Rectangle(50, 50, 100, 200, greenDrawAPI); greenRectangle.draw(); ``` 这样就可以将形状的抽象部分和实现部分分离了。如果需要增加一种新的形状或者实现,只需要创建一个新的类实现Shape或者DrawAPI接口即可,不需要修改原有的代码。 完整的代码示例可以参考以下链接:https://github.com/iluwatar/java-design-patterns/tree/master/bridge

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值