設計模式 - 橋接模式 (Structural Patterns - Bridge Pattern)

前言

GoF Design Pattern對於Bridge Pattern的定義如下:

decouple an abstraction from its implementation so that the two can vary independently", introduced by the Gang of Four

橋接模式最主要就是將你的抽象與實作分離,達到極致的解偶獨立。

Class Diagram

  • Abstraction: 將原本的主體抽換到只剩下虛擬的概念,例如(人類:只是吃喝拉撒睡的主體、遙控器:只是開機關機調整的主體)
    • RefineAbstraction: 根據不同的需求實作主體
  • Implementator: 將原本主體的實際功能抽離,成為這個的Hierarchy(繼承結構),例如(人類:人類的吃和拉撒睡拉出在此結構實作)
    • ConcreteImplementator: 根據不同的需求開發真實的行為

範例

此範例將英雄和英雄的行為抽離,並透過Bridge Pattern實踐

  • HeroAction: Implementator
    • FireHeroAction: ConcreteImplementator
    • IceHeroAction: ConcreteImplementator
  • Hero: Abstraction
    • Magician: RefineAbstraction
    • Warrior: RefineAbstraction
interface HeroAction {
    void kick();

    void slash();

    void beat();
}

class FireHeroAction implements HeroAction {

    @Override
    public void kick() {
        System.out.println("Fire kick");
    }

    @Override
    public void slash() {
        System.out.println("Fire slash");
    }

    @Override
    public void beat() {
        System.out.println("Fire beat");
    }
}

class IceHeroAction implements HeroAction {

    @Override
    public void kick() {
        System.out.println("Ice kick");
    }

    @Override
    public void slash() {
        System.out.println("Ice slash");
    }

    @Override
    public void beat() {
        System.out.println("Ice beat");
    }
}

abstract class Hero {
    private HeroAction heroAction;

    Hero() {
    }

    Hero(HeroAction heroAction) {
        this.heroAction = heroAction;
    }

    public void setHeroAction(HeroAction heroAction) {
        this.heroAction = heroAction;
    }

    public HeroAction getHeroAction() {
        return heroAction;
    }

    abstract void kick();

    abstract void attack();
}

class Magician extends Hero {

    Magician(HeroAction heroAction) {
        super(heroAction);
    }

    @Override
    void kick() {
        getHeroAction().kick();
    }

    @Override
    void attack() {
        getHeroAction().beat();
    }
}

class Warrior extends Hero {

    Warrior(HeroAction heroAction) {
        super(heroAction);
    }

    @Override
    void kick() {
        getHeroAction().kick();
    }

    @Override
    void attack() {
        getHeroAction().slash();
    }
}

public class Bridge {

    public static void main(String[] args) {
        Hero warrior = new Warrior(new IceHeroAction());
        Hero magician = new Magician(new FireHeroAction());
        warrior.attack();
        magician.attack();
    }
}

自我MurMur

在知道Bridge Pattern前我應該會這麼設計這功能,

  • 創建英雄介面,並且讓戰士和魔法師繼承與實作
  • 在實作的function中根據今天要水火源素去做if/else判斷

如果今天英雄新增到了一百個,突然在遊戲更新後發現其中一個元素有BUG的化,那不就完蛋了嗎(需要更改100個英雄的方法邏輯)。

如果今天元素也新增到了一百個,那行為的方法裡面的邏輯想到就讓人覺得害怕。

如果使用Bridge Patter將英雄轉為抽象概念(英雄只是一連串動作的主體),而在創建英雄時將行為主體注入。就算未來其中一個行為有Bug那只要更動一個Class,擴增英雄和行為都可以非常方便(增加繼承)

結論

所以橋接模式的主要目的

  • 將實作跟介面鬆綁
  • 抽象跟實作可以各自擴充,不會影響到對方
  • 對於實際的行為改變,不會影響呼叫端
    • 因為實際的行為已抽離,成為橋接的繼承結構

留言

這個網誌中的熱門文章

Java Lambda Map篇

(InterviewBit) System Design - Design Cache System

設計模式 - 享元模式 (Structural Patterns - Flyweight Design Pattern)