这几天重新去看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
第一个花里胡哨的功能
如果还有新的功能呢,依旧是继承,然后派生即可,而不是有多少种笔就新增多少类,那是非常糟糕的处理。
此时我们就实现了类的功能层次结构(新增功能)和实现层次结构(修改功能)的分离,以上我个人对桥接模式的一些理解。
这篇文章可以说是我写的比较认真的,写的时间也比较长,希望看到这里的各位点赞支持一下,大家一起进步。