技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

javaでのBridgeパターン

Bridgeパターンは、機能のクラス階層と実装のクラス階層を橋渡しするパターンです。
機能のクラス階層と実装のクラス階層を分けることで、実装毎に機能を書かなくて良くなりますし、その逆に機能毎に実装を書かなくて良くなります。
結果として、重複した記述を減らすことができ、保守性を向上させることができます。
 
今回は、RPGのダメージ計算を模したサンプルコードを作成してみました。
機能のクラス階層ではダメージの与え方を定義し、実装のクラス階層では具体的なダメージ計算式を定義しています。
Bridgeパターンの適用により、ダメージの与え方毎にダメージ計算式を書かなくて良くなっている点、逆にダメージ計算式毎にダメージの与え方を書かなくて良くなっている点に注目です。
 
【サンプルコード】
・DamageCalc.java
// ダメージ計算機能
public class DamageCalc {

    protected DamageCalcImpl damageCalcImpl;
    protected int damage = 0;

    public DamageCalc (DamageCalcImpl damageCalcImpl) {
        this.damageCalcImpl = damageCalcImpl;
    }

    protected void clearDamage() {
        damage = 0;
    }

    public int getDamage() {
        return this.damage;
    }

    public void damageCalc(int offenceValue, int defenceValue) {
        clearDamage();
        damage = damageCalcImpl.damageCalc(offenceValue,defenceValue);
    }

}
 
・MultipleDamageCalc.java
// ダメージ計算機能(連続攻撃に対応するための拡張)
public class MultipleDamageCalc extends DamageCalc {

    public MultipleDamageCalc(DamageCalcImpl damageCalcImpl) {
        super(damageCalcImpl);
    }

    public void multipleDamageCalc
        (int offenceValue, int defenceValue, int damageTimes) {
        clearDamage();
        for(int i = 0;i < damageTimes;i++) {
            damage += damageCalcImpl.damageCalc(offenceValue,defenceValue);
        }
    }

}
 
・DamageCalcImpl.java
// ダメージ計算の実装(抽象クラス)
public abstract class DamageCalcImpl {

    public abstract int damageCalc(int offenceValue, int defenceValue);

}
 
・NormalDamageCalcImpl.java
// ダメージ計算の実装(通常のダメージ計算)
public class NormalDamageCalcImpl extends DamageCalcImpl {

    public int damageCalc(int offenceValue, int defenceValue) {
        int damage = 0;
        damage = offenceValue - (defenceValue/2);
        if (damage < 0) {
            damage = 0;
        }
        return damage;
    }

}
 
・IgnoreDefenceDamageCalcImpl.java
// ダメージ計算の実装(防御無視のダメージ計算)
public class IgnoreDefenceDamageCalcImpl extends DamageCalcImpl {

    public int damageCalc(int offenceValue, int defenceValue) {
        int damage = 0;
        damage = offenceValue;
        if (damage < 0) {
            damage = 0;
        }
        return damage;
    }

}
 
・DamageCalcMain.java
// ダメージ計算のメインクラス
public class DamageCalcMain {
    public static void main(String[] args){

        int offenceValue = 100;
        int defenceValue = 50;
        int multipleDamageTimes = 4; // 連続攻撃の場合のみ使用

        NormalDamageCalcImpl normalDamageCalcImpl =
            new NormalDamageCalcImpl();
        IgnoreDefenceDamageCalcImpl ignoreDefenceDamageCalcImpl =
            new IgnoreDefenceDamageCalcImpl();

        System.out.println("■通常のダメージ計算(1回攻撃)");
        DamageCalc damageCalc1 = new DamageCalc(normalDamageCalcImpl);
        damageCalc1.damageCalc(offenceValue, defenceValue);
        System.out.println(" ダメージ:" + damageCalc1.getDamage());

        // 実装を独立させることで、実装毎に機能を書かなくて良い
        // (通常の1回攻撃メソッドと
        //   防御無視の1回攻撃メソッドを用意しなくて良い)
        System.out.println("■防御無視のダメージ計算(1回攻撃)");
        DamageCalc damageCalc2 =
            new DamageCalc(ignoreDefenceDamageCalcImpl);
        damageCalc2.damageCalc(offenceValue, defenceValue);
        System.out.println(" ダメージ:" + damageCalc2.getDamage());

        // 機能を独立させることで、機能毎に実装を書かなくて良い
        // (1回攻撃の防御無視メソッドと
        //   複数攻撃の防御無視メソッドを用意しなくて良い)
        System.out.println("■防御無視のダメージ計算(4回攻撃)");
        MultipleDamageCalc multipleDamageCalc1 =
            new MultipleDamageCalc(ignoreDefenceDamageCalcImpl);
        multipleDamageCalc1.multipleDamageCalc
            (offenceValue, defenceValue, multipleDamageTimes);
        System.out.println(" ダメージ:" + multipleDamageCalc1.getDamage());

    }
}
 
【実行結果】
■通常のダメージ計算(1回攻撃)
 ダメージ:75
■防御無視のダメージ計算(1回攻撃)
 ダメージ:100
■防御無視のダメージ計算(4回攻撃)
 ダメージ:400