桥接模式
模式定义
官方定义:桥接模式就是将抽象部分与现实部分进行分离,使它们可以独立变化。桥接模式将继承关系转化为关联关系,它降低了类与类之间的耦合度,减少了系统中类的数量,也减少了代码量。
优缺点
-
优点
-
将实现与抽象部分进行了分离。提高了比集成更好的解决方案,可以理解为将静态继承改为了动态组合。
-
提高了系统的可拓展性。在两个维度中改变其中任何一个都不会影响到另一个维度,也不需要修改原有的系统。
-
-
缺点
-
该模式的引入会增加系统的理解与设计难度,由于聚合关联关系在抽象层,所以要求开发者针对抽象进行设计与编程。
-
桥接模式要求必须正确的识别出两个维度的变化,因此其使用范围有一定的限制性。
-
模式使用场景
-
系统需要在抽象层和实现层增加更多的灵活性,避免两个层次之间建立静态的继承关系。
-
对于不希望通过继承导致类的数量过多的系统,桥接模式尤为适用。
-
一个类存在两个独立的维度,并且这两个维度都需要拓展。
上面的官方没有听懂很正常,下面会针对每一个名词每种情况进行分析,并且配合类图和代码例子给读者最清晰的思路。
举个栗子
就拿各个厂商品牌的手机来说,现在有 华为、小米、IPhone 三个品牌,这个时候我们需要生产这三个品牌的手机,需要怎么做呢?
这是符合上述中生产多个品牌手机的理想架构,很简单明了,首先定义一个Phone的抽象类,然后由各个品牌去进行具体的实现,我们只需要在客户端中进行调用就可以了。可是现在有个新的需求,我们生产的手机款式并不是单一的,每个品牌的手机有多种颜色,如果这个时候需要你来设计一个类图会怎样设计呢?根据上图中的架构可能会设计成这样。
我们可以看出每个品牌手机都有自己多种颜色的具体实现,这样设计的缺点就很明显的显露出来了,结合我们文章开头所描述的缺点可以一一对应上。上面设计中使用了静态继承 颜色和手机的具体实现中存在了静态继承不具备灵活性并且难以拓展,如果说后面又增加了新的颜色,那么就需要在每个品牌的手机颜色中都添加一个新的颜色实现类。 如果新增了一个品牌的手机,必须新增了OPPO手机,那么就会在需要多个类去继承OPPO品牌手机的类来实现多种颜色的手机制造。
所以在上面的总结汇总我们发现了此时的架构就存在两个维度即颜色和品牌,在这连个维度中拓展任何一方都会影响到另一个维度,拓展性差,而且会增加系统中类的数量增加代码量。
所以这个时候引进桥接设计模式就很有必要,下面我们再来看看文章开头所涉及到的加粗部分。
-
将抽象部分与现实部分进行分离
也就说将颜色和手机之间的继承关系取消,改为关联关系。
-
独立变化
如果将颜色和手机之间的静态继承关系改为关联关系,那么这两个维度就可以进行所以的增加、删除、修改,不会影响到另外一方,因为颜色这个维度是作为一个成员对象被引进到了手机类中了,没有存在继承关系。
-
桥接模式将继承关系转化为关联关系、降低了类与类之间的耦合度
不存在继承关系没有父子关系,两个维度平级,可以进行任意修改。
-
系统中类的数量
将继承改为关联,也就是将两个维度组合起来,不需要一个维度下面跟随另一个维度的多种实现。
如果这个时候我们再来理解文章开头所说的优缺点应该就可以很轻松的理解了。说了这么多我们接下来看一下关于这个例子使用桥接模式的类图
这个时候我们可以看到 Color不在继承与Phone,而且通过关联的方式将两个维度关联起来,这样无论哪个维度有变化了都不会影响到另外一个维度。下面看代码
package cn.hsh.study.abstraction;
import cn.hsh.study.color.PhoneColor;
/**
* @author shaohua
* @date 2021/4/8 20:46
*/
public abstract class Phone {
protected PhoneColor phoneColor;
public void setPhoneColor(PhoneColor phoneColor) {
this.phoneColor = phoneColor;
}
/**
* 打电话
*/
public abstract void call();
}
package cn.hsh.study.abstraction.impl;
import cn.hsh.study.abstraction.Phone;
/**
* @author shaohua
* @date 2021/4/8 20:47
*/
public class HuaWei extends Phone {
public void call() {
System.out.println(super.phoneColor.getColor() + "华为手机打电话");
}
}
package cn.hsh.study.abstraction.impl;
import cn.hsh.study.abstraction.Phone;
/**
* @author shaohua
* @date 2021/4/8 20:47
*/
public class Mi extends Phone {
public void call() {
System.out.println(super.phoneColor.getColor() + "小米手机打电话");
}
}
package cn.hsh.study.abstraction.impl;
import cn.hsh.study.abstraction.Phone;
/**
* @author shaohua
* @date 2021/4/8 20:47
*/
public class Oppo extends Phone {
public void call() {
System.out.println(super.phoneColor.getColor() + "oppo手机打电话");
}
}
package cn.hsh.study.color;
/**
* @author shaohua
* @date 2021/4/8 20:49
*/
public interface PhoneColor {
/**
* 获取颜色
* @return 颜色信息
*/
String getColor();
}
package cn.hsh.study.color.impl;
import cn.hsh.study.color.PhoneColor;
/**
* @author shaohua
* @date 2021/4/8 20:51
*/
public class Black implements PhoneColor {
public String getColor() {
return "黑色";
}
}
package cn.hsh.study.color.impl;
import cn.hsh.study.color.PhoneColor;
/**
* @author shaohua
* @date 2021/4/8 20:50
*/
public class Blue implements PhoneColor {
public String getColor() {
return "蓝色";
}
}
package cn.hsh.study.color.impl;
import cn.hsh.study.color.PhoneColor;
/**
* @author shaohua
* @date 2021/4/8 20:51
*/
public class Red implements PhoneColor {
public String getColor() {
return "红色";
}
}
package cn.hsh.study;
import cn.hsh.study.abstraction.impl.Mi;
import cn.hsh.study.color.PhoneColor;
import cn.hsh.study.color.impl.Blue;
/**
* @author shaohua
* @date 2021/4/8 19:59
*/
public class Client {
public static void main(String[] args) {
//红色的小米手机
Mi mi = new Mi();
PhoneColor miColor = new Blue();
mi.setPhoneColor(miColor);
mi.call();
}
}
下面是输出结果
可以看出来无论两个维度怎么变化,我们都可以在两个维度中分别构造出对应的对象,然后将其组合起来,桥接模式中所谓的桥无非就是一个维度中抽象层中所关联的另外一个维度的引用,比如Phone抽象类中的Color成员。
模式总结
桥接模式实现了抽象化与实现化的脱耦,让他们互相独立,不会影响到对方,对于独立变化的维度,所用桥接模式在合适不过了。
对于具体的抽象类,所做的改变,是不会影响到客户端的。