# 桥接模式

## 模式说明

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

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

\


## 结构

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

\


## 代码示例

```java
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());
    }
}
```
