什么是桥接模式?一文详解

目录

一.意图

二.结构

三.举例:产品上色

1.不用桥接模式的场景

2.使用桥接模式的场景

3.代码实现

①创建"抽象产品"(本质是一个抽象类)

②创建"抽象颜色"(本质是一个接口)

③创建两个具体的产品,比如产品A、产品B

④创建三个具体的颜色,比如红、蓝、绿

最终,进行测试

4.总结

四.软考真题

1.2009年上半年

题目

分析过程

正确答案

2.2013年下半年

题目

分析过程

正确答案

3.2017年下半年

题目

分析过程

正确答案


一.意图

将抽象部分与实现部分分离,使它们都可以独立地变化。

二.结构

下图只是一个大致的、通用的一个示意结构图,看起来懵是正常的,因此我们下面会举具体的例子。

三.举例:产品上色

我们就拿产品(比如产品需要根据具体情况上色)来举例。

说白了就是,给产品上色时,受两种因素影响:

  • 产品的类型(即:产品A、产品B、产品C之间,它们由于物理结构不同,上色工艺就不同)
  • 产品的颜色(即:红色的产品A就上红色,蓝色的产品A就上蓝色)

1.不用桥接模式的场景

如下图,可见此时类的数量就会爆炸(即需要创建很多的类)。

一共需要创建类的数量 = 1 + m + m*n

  • 1就是"抽象产品"(第一层)
  • m就是产品A、产品B.....这些(第二层)
  • m*n就是带颜色的产品的数量(即有m种产品,每种产品又有n种颜色)

思考:为什么会类的数量爆炸?

答案:因为颜色是在产品类中的,应该单独提取成"抽象颜色"这个模块,然后再与"抽象产品"进行一个关联(即桥接模式,这个关联就相当于一个桥)。

2.使用桥接模式的场景

如下图,此时类的数量就会大大减少

一共需要创建类的数量 = 1 + m + 1 +n

  • 1就是"抽象产品"
  • m就是产品A、产品B....这些
  • 1就是"抽象颜色"
  • n就是红、蓝、绿.....这些
    注意:菱形表示"抽象颜色"属于"抽象产品"的一部分,说白了就是"抽象产品"这个抽象类中,要定义一个属性,即"抽象颜色"。

注意:

"抽象颜色"这个抽象,用抽象类、接口来实现都可以,因为这俩都是抽象的东西,具体采用哪个,就需要具体情况具体分析。

3.代码实现

①创建"抽象产品"(本质是一个抽象类)

java 复制代码
//抽象产品
abstract class Product {
    //属性
    private String type;//产品类型:比如产品A、产品B、产品C
    protected Color color;//颜色:比如红、蓝、绿

    //方法
    public abstract void Operation();//上色方法

    //get、set
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public Color getColor() {
        return color;
    }
    public void setColor(Color color) {
        this.color = color;
    }
}

②创建"抽象颜色"(本质是一个接口)

java 复制代码
//抽象颜色
public interface Color {
    //根据"产品的类型"上色,具体上什么颜色,由Color接口的具体实现类决定
    public void OperationImp(String productType);
}

③创建两个具体的产品,比如产品A、产品B

java 复制代码
public class ProductA extends Product{
    @Override
    //实现父类Product定义的抽象方法(在Product中,抽象方法没有方法体,所以在这里给出)
    public void Operation() {
        //调用上色方法
        color.OperationImp(this.getType());//color继承自父类的属性color ,this代表ProductA的对象本身
    }
}
java 复制代码
public class ProductB extends Product{
    @Override
    //实现父类Product定义的抽象方法(在Product中,抽象方法没有方法体,所以在这里给出)
    public void Operation() {
        //调用上色方法
        color.OperationImp(this.getType());//color继承自父类的属性color ,this代表ProductB的对象本身
    }
}

④创建三个具体的颜色,比如红、蓝、绿

java 复制代码
public class Red implements Color{
    @Override
    //实现接口Color中定义的上色方法
    public void OperationImp(String productType) {
        System.out.println("正在给"+productType+"涂上红色");
    }
}
java 复制代码
public class Blue implements Color{
    @Override
    //实现接口Color中定义的上色方法
    public void OperationImp(String productType) {
        System.out.println("正在给"+productType+"涂上蓝色");
    }
}
java 复制代码
public class Green implements Color{
    @Override
    //实现接口Color中定义的上色方法
    public void OperationImp(String productType) {
        System.out.println("正在给"+productType+"涂上绿色");
    }
}

最终,进行测试

测试1:先来个红色的产品A

java 复制代码
public class Demo01Application {
    public static void main(String[] args) {
        //目标:此时我想要一个红色的产品A
        //1、创建一个具体的产品(比如产品A,即类型为A的产品)
        ProductA productA = new ProductA();
        //2、初始化产品的两个属性:产品类型、颜色(这是影响产品上色的两个因素)
        productA.setType("产品A");
        Color color = new Red();//这就是多态(说白了就是左边是通用的接口,右边是具体的实现类)
        productA.setColor(color);
        //3、执行上色方法
        productA.Operation();
    }
}

运行效果如下:

测试2:再来一个蓝色的产品B

java 复制代码
public class Demo01Application {
    public static void main(String[] args) {
        //目标:此时我想要一个蓝色的产品B
        //1、创建一个具体的产品(比如产品B,即类型为B的产品)
        ProductB productB = new ProductB();
        //2、初始化产品的两个属性:产品类型、颜色(这是影响产品上色的两个因素)
        productB.setType("产品B");
        Color color = new Blue();
        productB.setColor(color);//这就是多态(说白了就是左边是通用的接口,右边是具体的实现类)
        //3、执行上色方法
        productB.Operation();
    }
}

运行效果如下:

4.总结

  • 颜色本身就是属于产品的一个属性,但是由于我们产品有很多类型,每个类型又有很多颜色。当我们的上色工艺,是由产品类型 + 颜色这两个因素决定的,此时我们就需要创建很多类(因为红色的产品A、红色的产品B、蓝色的产品C、绿色的产品D等等,它们的上色工艺都不同,所以只要产品类型 or 颜色 有一个不同,就需要定义一个专门的上色方法),因此此时就需要创建很多个类(因为是相乘关系,即产品类型数量 * 颜色数量)
  • 此时为了解决这个问题,我们可以将颜色单独抽出为"抽象颜色"color(是一个接口),接口中定义一个上色方法(参数为"产品类型"),然后将这个color接口当做"抽象产品"的一个属性。此时我们可以定义很多颜色类去实现这个color接口,每个颜色类,根据接口的产品类型,再结合上自己的颜色,最终写出来独特的上色工艺(由产品类型+颜色决定)
  • 这样一看,核心思路就是,将颜色单独抽象为"抽象颜色"color接口,然后又把这个color接口当做"抽象产品"的一个属性。这就相当于一个桥梁,也是桥接模式的灵魂,可见十分灵活。
  • 而且要体会多态的思想,代码如下:

左面的Color是接口,右边是Color接口的具体实现类。说白了就是父 = 子 ,这种就是多态的思想。也只有这样,我们才能把这个color塞到"抽象产品"中当做属性。你要是不用多态,而是Blue blue = new Blue(); 将blue塞到"抽象产品"中当做属性,会报错,因为"抽象产品"类中,属性定义的是Color接口。

四.软考真题

1.2009年上半年

题目

分析过程

(1)this.imp

但注意,要用this关键字(this表示当前类的本身)区分开imp是属性还是形参。

因此第一空答案为:this.imp


(2)ImageImp

故第二空答案为:ImageImp


(3)imp.doPaint(m)

此时我们可见,显示像素矩阵m的方法在抽象类ImageImp中,此时BMP对象如何获取?

别忘了,我们BMP继承了Image类,Image类中就有,即属性imp。

因此,此时这个BMP类,可以直接使用父类对象imp,去调用显示像素矩阵的方法。

因此第三空的答案为:imp.doPaint(m)


(4)new BMP()

根据多态的思想,再结合桥接模式图,可轻松得到答案:

因为人家说要查看bmp类型的图像文件,所以此时要创建BMP对象

故第四空答案为:new BMP()


(5)new WinImp()

思考过程同上,人家要在Windows操作系统上查看,因此要创建WinImp类的对象

(6)image1.setImp(imageImp1)

由于Image类需要ImageImp当做属性,因此很清晰就能得到这一空的答案。

(7)17

  • Image占一个
  • ImageImp占一个
  • BMP、GIF等等,共有10个(题目给的)
  • WinImp、LinuxImp,共有5个

综上,一共1+1+10+5 = 17个

正确答案

可见,我们的上述答案,和下面的正确答案一样。

2.2013年下半年

题目

分析过程

(1)interface

我们往后看,发现都有的类实现了Drawing了,那Drawing肯定就是接口了。

故第一空的答案为:interface


(2)(3)

具体定义了哪两个方法,可以去看一下它的实现类,如下:

因此可见:

  • 第二空的答案为:public void drawLine(double x1, double y1,double x2, double y2)
  • 第三空的答案为:public void drawCircle(double x, double y, double r)

(4)(5)

然后再结合这个规则,我们还需要去找一下具体的方法在哪里:

  • 第四空的答案为:DP1.draw_a_circle(x, y, r)
  • 第五空的答案为:DP2.drawcircle(x, y, r)

(6)

并且,这个draw方法被子类又实现了一遍,并且Shape本身就是抽象类,所以draw方法肯定是抽象的(需要用abstract修饰),且需要子类能访问,故还要用public修饰。通过子类能发现draw方法的返回值是void

因此第六空的答案为:abstract public void draw()

正确答案

经过对比,发现我们上述的答案和正确答案一致。(下面的答案没写public关键字,最好带上)

3.2017年下半年

题目

分析过程

(1)abstract void doPaint(Matrix m)

由于Implementor是抽象类、且该方法没有方法体,故这个方法肯定是abstract修饰的。再根据该抽象类的两个子类,可得该方法的方法名为doPaint,且返回值为void,形参为Matrix m

因此第一空的答案为:abstract void doPaint(Matrix m)


(2)imp.doPaint(m)

由于GIFImage继承了Image类,所以就有imp这个属性了(是Implementor抽象类的对象),因此就可以调用其中的doPaint方法来显示像素矩阵了。

故第二空的答案为:imp.doPaint(m)


(3)(4)(5)

由于人家要看gif类型的图像,所以我们要创建GIFImage类的对象。而且人家要在linux操作系统上查看,因此我们必须创建LinuxImp类的对象。最后再将imageImp放入image中充当属性。故:

  • 第三空的答案:new GIFImage()
  • 第四空的答案:new LinuxImp()
  • 第五空的答案:image.setImp(imageImp)

正确答案

将上述我们的答案,和下面的正确答案对比,发现全对。

相关推荐
cgsthtm1 天前
VMWare选择桥接模式解决虚拟机无法上网
桥接模式·vmware·网络适配器·虚拟机ip地址·虚拟机网络设置
多加点辣也没关系5 天前
设计模式-桥接模式
设计模式·桥接模式
蜡笔小马6 天前
04.C++设计模式-桥接模式
c++·设计模式·桥接模式
雪度娃娃7 天前
结构型设计模式——桥接模式
c++·设计模式·桥接模式
wuxuanok21 天前
VMware 桥接模式 - 【复制物理网络连接状态】选项详解 及不开启时的手动配置
桥接模式
wuxuanok22 天前
VMware NAT模式 桥接模式
桥接模式
洛洛呀。23 天前
Kali系统桥接模式下相关网络故障
linux·服务器·桥接模式
ximu_polaris23 天前
设计模式(C++)-结构型模式-桥接模式
c++·设计模式·桥接模式
geovindu1 个月前
go: Bridge Pattern
开发语言·设计模式·golang·软件构建·桥接模式