Collin Nam


设计模式之-桥接模式

Frank 2019-07-16 963浏览 0条评论
首页/ 正文
分享到: / / / /

桥接模式的定义

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

     桥接模式是一种很实用的结构型设计模式,如果软件系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来,使两者可以独立扩展,让系统更加符合“单一职责原则”。与多层继承方案不同,它将两个独立变化的维度设计为两个独立的继承等级结构,并且在抽象层建立一个抽象关联,该关联关系类似一条连接两个独立继承结构的桥,故名桥接模式。

     桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联取代了传统的多层继承,将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同时有效控制了系统中类的个数

 

桥接模式的结构 桥接模式包含以下4个角色:

Abstraction(抽象类)

RefinedAbstraction(扩充抽象类)

Implementor(实现类接口)

ConcreteImplementor(具体实现类)

 

桥接模式概述

分析

     蜡笔:颜色和型号两个不同的变化维度(即两个不同的变化原因)耦合在一起,无论是对颜色进行扩展还是对型号进行扩展都势必会影响另一个维度

     毛笔:颜色和型号实现了分离,增加新的颜色或者型号对另一方没有任何影响

 

桥接模式的结构

 

桥接模式实现

典型的实现类接口代码:

public interface Implementor {
    public void operationImpl();
}

典型的具体实现类代码:

public class ConcreteImplementor implements Implementor {
    public void operationImpl() {
        //具体业务方法的实现
    }
}

典型的抽象类代码:

public abstract class Abstraction {
    protected Implementor impl; //定义实现类接口对象
	
    public void setImpl(Implementor impl) {
        this.impl=impl;
    }
	
    public abstract void operation(); //声明抽象业务方法
}

典型的扩充抽象类(细化抽象类)代码:
 

public class RefinedAbstraction extends Abstraction {
    public void operation() {
        //业务代码
        impl.operationImpl(); //调用实现类的方法
        //业务代码
    }
}

 

桥接模式的应用实例

     某软件公司要开发一个跨平台图像浏览系统,要求该系统能够显示BMP、JPG、GIF、PNG等多种格式的文件,并且能够在Windows、Linux、UNIX等多个操作系统上运行。系统首先将各种格式的文件解析为像素矩阵(Matrix),然后将像素矩阵显示在屏幕上,在不同的操作系统中可以调用不同的绘制函数来绘制像素矩阵。另外,系统需具有较好的扩展性,以便在将来支持新的文件格式和操作系统。试使用桥接模式设计该跨平台图像浏览系统。

实例类图

 

实例代码

(1) Matrix:像素矩阵类,辅助类

package designpatterns.bridge.image;

/**
 * @Author Frank
 * @Description
 * @Date: Create in  2019-07-16 15:50
 */
public class Matrix {
    //此处省略一万字
}

(2) ImageImp:抽象操作系统实现类,充当实现类接口

package designpatterns.bridge.image;

/**
 * @Author Frank
 * @Description
 * @Date: Create in  2019-07-16 15:51
 */
public interface ImageImp {

    public void doPaint(Matrix matrix);
}

(3) WindowsImp:Windows操作系统实现类,充当具体实现类

package designpatterns.bridge.image;

/**
 * @Author Frank
 * @Description
 * @Date: Create in  2019-07-16 15:52
 */
public class WindowsImageImp implements ImageImp {
    @Override
    public void doPaint(Matrix matrix) {
        System.out.println("调用windows操作系统显示图像");
    }
}

(4) LinuxImp:Linux操作系统实现类,充当具体实现类

package designpatterns.bridge.image;

/**
 * @Author Frank
 * @Description
 * @Date: Create in  2019-07-16 15:53
 */
public class LinuxImageImp implements ImageImp {
    @Override
    public void doPaint(Matrix matrix) {
        System.out.println("调用Linux系统显示图像");
    }
}

(5) MacOsImp:UNIX操作系统实现类,充当具体实现类

package designpatterns.bridge.image;

/**
 * @Author Frank
 * @Description
 * @Date: Create in  2019-07-16 15:55
 */
public class MacOsImageImp implements ImageImp {
    @Override
    public void doPaint(Matrix matrix){
        System.out.println("调用macOs系统显示图像");
    }
}

(6) Image:抽象图像类,充当抽象类

package designpatterns.bridge.image;

/**
 * @Author Frank
 * @Description
 * @Date: Create in  2019-07-16 15:56
 */
public abstract class Image {
    protected ImageImp imageImp;

    public void setImageImp(ImageImp imageImp){
        this.imageImp=imageImp;
    }

    public abstract void parseFile(String fileName);

}

(7) JPGImage:JPG格式图像类,充当扩充抽象类

package designpatterns.bridge.image;

/**
 * @Author Frank
 * @Description
 * @Date: Create in  2019-07-16 16:06
 */
public class JPGImage extends Image {
    @Override
    public void parseFile(String fileName) {
        Matrix matrix=new Matrix();
        imageImp.doPaint(matrix);
        System.out.println(fileName+",格式为JPG");
    }
}

(8) PNGImage:PNG格式图像类,充当扩充抽象类

package designpatterns.bridge.image;

/**
 * @Author Frank
 * @Description
 * @Date: Create in  2019-07-16 16:06
 */
public class PNGImage extends Image{
    @Override
    public void parseFile(String fileName) {
        Matrix matrix=new Matrix();
        imageImp.doPaint(matrix);
        System.out.println(fileName+",格式为PNG");
    }
}

(9) BMPImage:BMP格式图像类,充当扩充抽象类

package designpatterns.bridge.image;

/**
 * @Author Frank
 * @Description
 * @Date: Create in  2019-07-16 16:28
 */
public class BMPImage extends Image {
    @Override
    public void parseFile(String fileName) {
        Matrix matrix = new Matrix();
        imageImp.doPaint(matrix);
        System.out.println(fileName + ",格式为BMP");
    }
}

(10) GIFImage:GIF格式图像类,充当扩充抽象类

package designpatterns.bridge.image;

/**
 * @Author Frank
 * @Description
 * @Date: Create in  2019-07-16 16:28
 */
public class GIFImage extends Image {

    @Override
    public  void parseFile(String filename){
        Matrix matrix=new Matrix();
        imageImp.doPaint(matrix);
        System.out.println(filename+",文件格式为GIF");
    }

}

(11) Client:客户端测试类

package designpatterns.bridge.image;

import java.io.File;

/**
 * @Author Frank
 * @Description
 * @Date: Create in  2019-07-16 16:34
 */
public class ImageClient {
    public static void main(String[] args) {
        File file = new File("/Users/frank/Desktop/timg.jpeg");
        ImageImp imageImp = new WindowsImageImp();
        Image image = new JPGImage();
        image.setImageImp(imageImp);
        image.parseFile(file.getName());
    }
}

 

桥接模式与适配器模式的联用

 

     在软件开发中,适配器模式通常可以与桥接模式联合使用。适配器模式可以解决两个已有接 口间不兼容问题,在这种情况下被适配的类往往是一个黑盒子,有时候我们不想也不能改变 这个被适配的类,也不能控制其扩展。适配器模式通常用于现有系统与第三方产品功能的集 成,采用增加适配器的方式将第三方类集成到系统中。桥接模式则不同,用户可以通过接口 继承或类继承的方式来对系统进行扩展。 桥接模式和适配器模式用于设计的不同阶段,桥接模式用于系统的初步设计,对于存在两个 独立变化维度的类可以将其分为抽象化和实现化两个角色,使它们可以分别进行变化;而在 初步设计完成之后,当发现系统与已有类无法协同工作时,可以采用适配器模式。但有时候 在设计初期也需要考虑适配器模式,特别是那些涉及到大量第三方应用接口的情况。

 

 

下面通过一个实例来说明适配器模式和桥接模式的联合使用:

     在某系统的报表处理模块中,需要将报表显示和数据采集分开,系统可以有多种报表显示方 式也可以有多种数据采集方式,如可以从文本文件中读取数据,也可以从数据库中读取数 据,还可以从Excel文件中获取数据。如果需要从Excel文件中获取数据,则需要调用与Excel相 关的API,而这个API是现有系统所不具备的,该API由厂商提供。使用适配器模式和桥接模式 设计该模块。 在设计过程中,由于存在报表显示和数据采集两个独立变化的维度,因此可以使用桥接模式 进行初步设计;为了使用Excel相关的API来进行数据采集则需要使用适配器模式。系统的完整 设计中需要将两个模式联用,如图所示:

 

 

桥接模式的优缺点与适用环境

模式优点

分离抽象接口及其实现部分 可以取代多层继承方案,极大地减少了子类的个数 提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,不需要修改原有系统,符合开闭原则

 

模式缺点

会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程 正确识别出系统中两个独立变化的维度并不是一件容易的事情

模式适用环境

 

需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系 抽象部分和实现部分可以以继承的方式独立扩展而互不影响 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立地进行扩展 不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统

最后修改:2019-07-16 11:51:24 © 著作权归作者所有
如果觉得我的文章对你有用,请随意赞赏
扫一扫支付

上一篇

发表评论

说点什么吧~

评论列表

还没有人评论哦~赶快抢占沙发吧~