桥接模式

模式说明

当一个事物可以通过多个维度描述时,要避免多个维度层层继承该事物的抽象类,而应该将这些不同的维度从事物中分离出来独立变化。例如电脑可以通过不同品牌和不同软件描述,可以将电脑作为一个PC抽象类,以品牌为主体,不同品牌继承该PC类如ApplePC。软件分离出来成为一个独立的抽象类Software,具体软件继承该Software抽象类,例如Browser类。在PC抽象类中以组合形式拥有Software,并通过调用Software的方法,实施Software中的行为。在UML图中分离事物抽象类通过带组合箭头的线与主体事物抽象类连接,故名桥接。

本示例演示上述PC场景。如果希望增加一个华为品牌PC只需增加继承PC类的HuaweiPC类即可,无需改动其他类。同理希望增加视频软件时,也只需要增加VideoPlayer类而无需关注品牌。这就是各自独立变化。另,本示例中主体事物PC只持有一个Software实例,如果想同时持有多个Software实例,可以声明为集合类型(如List),然后增加相应的add方法。

结构

抽象主体事物类: 主体事物,类内声明一个以protected修饰的分离事物(以抽象类型声明)。声明一个用于实施分离事物行为的抽象方法。 具体主体事物类: 继承抽象主体事物类,实现抽象方法。 抽象分离事物类: 能够描述主体事物的某个维度的事物,声明自己的行为。 具体分离事物类: 继承抽象分离事物类,实现抽象方法。

代码示例

package com.yukiyama.pattern.structure;

/**
 * 桥接模式
 */
public class BridgeDemo {

    public static void main(String[] args) {
        // 声明一个PC(主体事物)
        PC pc = new ApplePC();
        // 声明一个软件(分离事物)
        Software soft1 = new Browser();
        // 将软件组合进PC中(主体持有分离)
        pc.setSoftware(soft1);
        // 通过调用主体事物的方法来间接执行分离事物的方法
        // 输出"启动: Browser"
        pc.run();
        // 增加一个软件后,同上
        Software soft2 = new MusicPlayer();
        pc.setSoftware(soft2);
        // 输出"启动: MusicPlayer"
        pc.run();
    }

}

/**
 * 主体事物抽象类
 * 以PC为例,内部声明protected修饰的分离事物Software。非抽象方法
 * setSoftware()传入分离事物使得主体持有分离。声明用于实施Software
 * 行为抽象方法run()。
 */
abstract class PC{
    protected Software soft;
    
    public void setSoftware(Software soft) {
        this.soft = soft;
    }
    public abstract void run();
}

/**
 * 主体事物具体类
 * 继承抽象主体事物类,实现抽象方法run,内部实际调用Software自身的run。
 */
class ApplePC extends PC{
    @Override
    public void run() {
        this.soft.run();
    }
}

/**
 * 抽象分离事物类
 * 有自身的属性和方法。
 * 下例是从软件维度描述PC的软件抽象类。
 */
abstract class Software{
    private String name;
    
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public abstract void run();
}

/**
 * 具体分离事物类
 * 继承抽象分离事物类,实现抽抽象方法。
 * 下例是浏览器类。
 */
class Browser extends Software{
    public Browser() {
        this.setName("Browser");
    }
    @Override
    public void run() {
        System.out.println("启动: "+this.getName());
    }
}

/**
 * 具体分离事物类
 * 下例是音乐播放器类。
 */
class MusicPlayer extends Software{
    public MusicPlayer() {
        this.setName("MusicPlayer");
    }
    @Override
    public void run() {
        System.out.println("启动: "+this.getName());
    }
}

Last updated