授课语音

适配器模式与桥接模式的区别

适配器模式(Adapter Pattern)和桥接模式(Bridge Pattern)都是结构型设计模式,它们的目标都是通过某种方式将两个不兼容的接口连接起来,使得客户端能够使用它们,但这两种模式的应用场景和设计思想有所不同。


1. 适配器模式(Adapter Pattern)

适配器模式的目的是将一个类的接口转换成客户端所期望的接口,从而使得原本接口不兼容的两个类能够协同工作。适配器模式通常是在现有系统的基础上增加新的功能,目的是“适配”现有接口,使其符合目标接口。

1.1 应用场景

  • 当你希望将一个已有的类与另一个接口兼容时,但不希望修改现有的类。
  • 在系统中有多个不同的类实现相似的功能,但接口不兼容时。

1.2 设计思想

  • 使用适配器来“包裹”原有的类,重新定义一个与目标接口兼容的接口,从而实现对原有类的适配。
  • 适配器通常是作为客户端和服务提供者之间的“桥梁”存在,它不改变服务提供者的行为,只改变服务接口的形式。

2. 桥接模式(Bridge Pattern)

桥接模式的目的是将抽象部分与实现部分分离,使得它们可以独立地变化。通过桥接模式,可以在不改变抽象部分的情况下,改变其实现方式,或者在不改变实现部分的情况下,改变抽象部分。

2.1 应用场景

  • 需要独立扩展抽象和实现部分的类,并且抽象部分和实现部分都有多个变化维度时。
  • 当一个类有多个变化维度,而这些变化维度经常会发生变化时,桥接模式可以有效解决代码爆炸的问题。

2.2 设计思想

  • 抽象和实现分离,通过组合的方式将它们关联起来。
  • 抽象层定义高层次的接口,而实现层定义具体的实现,两者独立变化,避免了多重继承导致的复杂性。

3. 适配器模式与桥接模式的区别

特性 适配器模式(Adapter Pattern) 桥接模式(Bridge Pattern)
主要目的是 转换接口,使得不兼容的接口能够协同工作。 分离抽象和实现,使得两者可以独立变化。
工作方式 在客户端和服务提供者之间提供一个适配器,转换接口。 使用桥接实现类与抽象类解耦,允许独立变化抽象和实现的维度。
应用场景 用于两个接口不兼容的情况下。 用于有多个维度的变化,且每个维度都有多个变体时。
实现形式 通过组合现有的类,将其接口转换为目标接口。 通过组合抽象类和实现类,解耦它们的变化。
是否改变原有类 不改变原有类的代码,只是调整接口。 不改变原有类的代码,通过桥接方式将抽象部分与实现部分分离。

4. 代码示例:适配器模式

4.1 代码案例

// 目标接口
interface MediaPlayer {
    void play(String audioType, String fileName);
}

// 被适配的类
class MediaAdapter implements MediaPlayer {
    AdvancedMediaPlayer advancedMusicPlayer;

    public MediaAdapter(String audioType) {
        if(audioType.equalsIgnoreCase("vlc") ){
            advancedMusicPlayer = new VlcPlayer();
        }
        else if(audioType.equalsIgnoreCase("mp4")){
            advancedMusicPlayer = new Mp4Player();
        }  
    }

    @Override
    public void play(String audioType, String fileName) {
        if(audioType.equalsIgnoreCase("vlc")){
            advancedMusicPlayer.playVlc(fileName);
        }
        else if(audioType.equalsIgnoreCase("mp4")){
            advancedMusicPlayer.playMp4(fileName);
        }
    }
}

// 高级媒体播放器接口
interface AdvancedMediaPlayer {
    void playVlc(String fileName);
    void playMp4(String fileName);
}

// 高级媒体播放器的实现类
class VlcPlayer implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        System.out.println("Playing vlc file: " + fileName);
    }

    @Override
    public void playMp4(String fileName) {
        // 不支持播放 MP4 格式
    }
}

class Mp4Player implements AdvancedMediaPlayer {
    @Override
    public void playVlc(String fileName) {
        // 不支持播放 VLC 格式
    }

    @Override
    public void playMp4(String fileName) {
        System.out.println("Playing mp4 file: " + fileName);
    }
}

// 客户端代码
public class AdapterPatternDemo {
    public static void main(String[] args) {
        AudioPlayer audioPlayer = new AudioPlayer();

        audioPlayer.play("mp3", "beyond the horizon.mp3");
        audioPlayer.play("mp4", "alone.mp4");
        audioPlayer.play("vlc", "far far away.vlc");
        audioPlayer.play("avi", "mind me.avi");
    }
}

4.2 代码解析

在这个示例中,我们通过 MediaAdapter 类实现了适配器模式,将 MediaPlayerAdvancedMediaPlayer 不兼容的接口适配了起来。通过适配器类,AudioPlayer 客户端可以统一使用 play 方法播放不同格式的音频。


5. 代码示例:桥接模式

5.1 代码案例

// 抽象类
abstract class Shape {
    protected DrawingAPI drawingAPI;

    protected Shape(DrawingAPI drawingAPI) {
        this.drawingAPI = drawingAPI;
    }

    public abstract void draw();
    public abstract void resizeByPercentage(double percentage);
}

// 实现类接口
interface DrawingAPI {
    void drawCircle(double x, double y, double radius);
}

// 具体实现类
class DrawingAPI1 implements DrawingAPI {
    @Override
    public void drawCircle(double x, double y, double radius) {
        System.out.println("Drawing API1 Circle at (" + x + ", " + y + ") with radius " + radius);
    }
}

class DrawingAPI2 implements DrawingAPI {
    @Override
    public void drawCircle(double x, double y, double radius) {
        System.out.println("Drawing API2 Circle at (" + x + ", " + y + ") with radius " + radius);
    }
}

// 具体抽象类
class Circle extends Shape {

    private double x, y, radius;

    public Circle(double x, double y, double radius, DrawingAPI drawingAPI) {
        super(drawingAPI);
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    @Override
    public void draw() {
        drawingAPI.drawCircle(x, y, radius);
    }

    @Override
    public void resizeByPercentage(double percentage) {
        radius *= percentage;
    }
}

// 客户端代码
public class BridgePatternDemo {
    public static void main(String[] args) {
        Shape circle1 = new Circle(5, 10, 2, new DrawingAPI1());
        Shape circle2 = new Circle(10, 20, 4, new DrawingAPI2());

        circle1.draw();
        circle2.draw();
    }
}

5.2 代码解析

在这个示例中,Shape 类定义了抽象的绘图方法,而 DrawingAPI 接口和它的实现类 DrawingAPI1DrawingAPI2 提供了具体的绘图实现。通过桥接模式,我们将抽象部分 Shape 和实现部分 DrawingAPI 解耦,使得两者可以独立变化。


6. 总结

  • 适配器模式 用于转换接口,使得不同接口的类可以协同工作。它通过适配器将现有类的接口转换为目标接口。
  • 桥接模式 用于解耦抽象和实现部分,使得它们可以独立变化。它通过组合将抽象和实现部分分开,避免了复杂的继承关系。
去1:1私密咨询

系列课程: