Bridgeパターン

個人的にはC++時代に有効だった手法かなと。
C#やJavaで使うとなるとインターフェースが存在するため、直接インターフェースを実装せずに1つオブジェクトを挟む感じでしょうか。

通常の継承

abstract class SpellBase
{
    abstract public int Low();
    abstract public int Middle();
    abstract public int High();
}

上記を継承したクラスを作成する場合、

class Mera : SpellBase
{
    public override int Low() {
        int value;
        // 色々な計算
        return value;
    }

    public override int Middle() {
        int value;
        // 色々な計算
        return value;
    }

    public override int High() {
        int value;
        // 色々な計算
        return value;
    }
}
class Gira : SpellBase
{
    public override int Low() {
        int value;
        // 色々な計算
        return value;
    }

    public override int Middle() {
        int value;
        // 色々な計算
        return value;
    }

    public override int High() {
        int value;
        // 色々な計算
        return value;
    }
}

上記でも問題ないが、例えば「ハイテンション状態なら、各戻り値を2倍する」。とかの仕様が追加になると、使用側もしくは各メソッドで判定が必要になる。
そこでBridgeパターンが登場です。

Bridgeパターン

interface ISpellImplementer
{
    int Low();
    int Middle();
    int High();
}

橋渡しクラス

class SpellBridge
{
    protected ISpellImplementer _spellImple;

    public SpellBridge(ISpellImplementer spellImple) {
        this._spellImple = spellImple;
    }

    public virtual int Low() {
        return this._spellImple.Low();
    }

    public virtual int Middle() {
        return this._spellImple.Middle();
    }

    public virtual int High() {
        return this._spellImple.High();
    }
}

計算式実装クラス

class Mera : ISpellImplementer
{
    public int Low() {
        int value;
        // 色々な計算
        return value;
    }

    public int Middle() {
        int value;
        // 色々な計算
        return value;
    }

    public int High() {
        int value;
        // 色々な計算
        return value;
    }
}
class Gira : ISpellImplementer
{
    public int Low() {
        int value;
        // 色々な計算
        return value;
    }

    public int Middle() {
        int value;
        // 色々な計算
        return value;
    }

    public int High() {
        int value;
        // 色々な計算
        return value;
    }
}

ハイテンション状態で使用するクラス

class SpellBridgeWithHighTension : SpellBridge
{
    public SpellBridgeWithHighTension(ISpellImplementer spellImple)
        :base(spellImple) {
    }

    public override int Low() {
        int value = this._spellImple.Low();
        return value * 2;
    }

    public override int Middle() {
        int value = this._spellImple.Middle();
        return value * 2;
    }

    public override int High() {
        int value = this._spellImple.High();
        return value * 2;
    }
}

ハイテンション状態かどうかを橋渡しクラスで判断させる場合

各メソッドでハイテンションかどうかを判断して処理を記述する必要があります。

class SpellBridge
{
    protected ISpellImplementer _spellImple;

    public SpellBridge(ISpellImplementer spellImple) {
        this._spellImple = spellImple;
    }

    public virtual int Low() {
        int value = this._spellImple.Low();
        if (IsHighTension()) {
            return value * 2;
        }
        return value;
    }

    public virtual int Middle() {
        int value = this._spellImple.Middle();
        if (IsHighTension()) {
            return value * 2;
        }
        return value;
    }

    public virtual int High() {
        int value = this._spellImple.High();
        if (IsHighTension()) {
            return value * 2;
        }
        return value;
    }
}
IsHighTension()はハイテンションかどうかを取得するメソッドを想定。

このサンプルではあまりメリットはありませんが、Bridgeパターンを使用することで変更箇所が絞れています。
(ハイテンション時の記述がSpellBridgeWithHighTensionクラスに限られている)
後々、実行時間を測定するケースが出てきそうな処理などはこういう風に実装しておくと、試験用・実運用などで切り分けが簡単になりそうです。

このエントリーをはてなブックマークに追加
にほんブログ村 IT技術ブログへ

コメント

メールアドレスが公開されることはありません。 が付いている欄は必須項目です