技術とか戦略とか

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

javaでのFacadeパターン

Facadeクラスとは、使い方が複雑になっているクラス群をまとめ、使いやすい形のインターフェースとして外部に提供するクラスのことを指します。
デザインパターンでは、このFacadeクラスを利用するパターンをFacadeパターンと呼びます。
(ちなみに、Facadeは「窓口」を意味する単語です)
 
サンプルコードとして、RPGのダメージ計算を模したプログラムを作成してみました。
RPGのダメージ計算は複雑で、そのRPGに詳しくない人が正しく計算式を実装するのは困難なのですが、Facadeクラスを用いることにより、Facadeクラスの利用者は詳しい知識を持たずとも正しく計算式を実装することが可能となります。
 
【サンプルコード】
・PhysicsBaseDamageCalc.java
public final class PhysicsBaseDamageCalc {

    private int baseDamage = 0;

    public PhysicsBaseDamageCalc(int physicsPower) {
        baseDamage = physicsPower / 2; //攻撃力の半分がダメージ
    }

    public int getBaseDamage() {
        return baseDamage;
    }

}
 
・MagicBaseDamageCalc.java
public final class MagicBaseDamageCalc {

    private int baseDamage = 0;

    public MagicBaseDamageCalc(int magicID) {
        if (magicID == 0) { //魔法「FireL1」
            baseDamage = 15;
        } else if (magicID == 1) { //魔法「FireL2」
            baseDamage = 60;
        } else if (magicID == 2) { //魔法「FireL3」
            baseDamage = 120;
        } else { //例外処理
            System.out.println("指定された魔法IDは未実装です");
            System.exit(1);
        }
    }

    public int getBaseDamage() {
        return baseDamage;
    }

}
 
・DamageRandomize.java
import java.util.Random;

public final class DamageRandomize {

    private int damage = 0;

    public DamageRandomize(int baseDamage) {
        // 7/8、8/8、9/8の何れかの値をかけてランダム化
        damage = baseDamage * (new Random().nextInt(3) + 7) / 8;
    }

    public int getDamage() {
        return damage;
    }
}
 
・DamageCalcFacade.java
public final class DamageCalcFacade {

    private int damage = 0;

    public DamageCalcFacade (int physicsPower,int magicID) {
        int baseDamage = 0;
        if (physicsPower >= 0 || magicID == -1) { //物理攻撃
            baseDamage = new PhysicsBaseDamageCalc(physicsPower)
                              .getBaseDamage();
        } else if (physicsPower == -1 || magicID >= 0) { //魔法攻撃
            baseDamage = new MagicBaseDamageCalc(magicID)
                              .getBaseDamage();
        } else { //例外処理
            System.out.println("不正なダメージ計算です");
            System.exit(1);
        }
        damage = new DamageRandomize(baseDamage).getDamage();
    }

    public int getDamage() {
        return damage;
    }
}
 
・DamageCalcMain.java
public class DamageCalcMain {
    public static void main(String[] args){

        int physicsPower = -1;
        int magicID = -1;
        int damage = 0;

        // 引数から物理攻撃力、魔法IDを取得
        if (args.length == 2) {
            physicsPower = Integer.parseInt(args[0]);
            magicID = Integer.parseInt(args[1]);
        }

        // ダメージ計算→計算式を知らないとこのように実装できない
        /*
        int baseDamage = 0;
        if (physicsPower >= 0 || magicID == -1) { //物理攻撃
            baseDamage = new PhysicsBaseDamageCalc(physicsPower)
                              .getBaseDamage();
        } else if (physicsPower == -1 || magicID >= 0) { //魔法攻撃
            baseDamage = new MagicBaseDamageCalc(magicID)
                              .getBaseDamage();
        } else { //例外処理
            System.out.println("不正なダメージ計算です");
            System.exit(1);
        }
        damage = new DamageRandomize(baseDamage).getDamage();
        */

        // 利用者側で複雑な計算式を考えたくないので、Facadeクラスに任せる
        damage = new DamageCalcFacade(physicsPower,magicID).getDamage();

        System.out.println("ダメージは"+damage);
        System.exit(0);

    }
}
 
【実行結果】 ※第1引数に-1、第2引数に1を指定した場合
ダメージは52