読者です 読者をやめる 読者になる 読者になる

ヒビノログ

個人的なメモを淡々と記録していくブログ。最近はLaravelやスマートフォンの話題など。

仮面ライダードライブとゴーストで学ぶDI

diary PHP

この記事は、DI(Dependency Injection)を、仮面ライダードライブとゴーストを使って説明してみようというコーナーです。よろしくお願いします。

まず、DIについて。

ソフトウェアにおけるデザインパターンの1つであるDIは「依存性の注入」と訳されることが多いですが、DependencyWikipedia によると以下のように記載されています。

A dependency is an object that can be used (a service).

Dependency はサービスオブジェクトである」と。ですから Dependency Injection は「オブジェクト(サービス)の注入」としたほうが日本語としてもわかりやすいのではと思います。

次に、仮面ライダードライブとゴーストについて。
昨年9月まで放送されていた仮面ライダードライブは、主人公泊進ノ介人工知能(ベルトさん)を持ったベルト(ドライブドライバー)と、ベルトさんが使役するシフトカーの能力を使ってドライブに変身し、敵に立ち向かうというストーリーです。

対して、現在放送中の仮面ライダーゴーストは、主人公天空寺タケルが歴史上(あるいは物語に出てくる)の英雄・偉人の力を借りながら敵に立ち向かうストーリーです。主人公は、宮本武蔵エジソンロビンフッドといった英雄や偉人の能力が詰め込まれた「ゴースト眼魂(アイコン)」という物体をベルト(ゴーストドライバー)に装着することで変身し、彼らの力や技を使いながら敵と戦います。

DIの観点から見たドライブとゴーストの違い。
仮面ライダードライブではベルト自体に人工知能(ベルトさん)があらかじめ組み込まれており、ドライブとベルトさんは一心同体と言っても良い関係でした。これをプログラムで表すとこんな感じになるかと思います。

class 仮面ライダードライブ {
    protected $core;

    public function __construct() {
        // 機能(ベルトさん(人工知能))はあらかじめベルトに組み込まれている
        $this->core = new ベルトさん();
    }
    public function doSomething() {
        return $this->core->doSomething();
    }
    ...
}

クラス内で機能(ベルトさん)を生成しており、仮面ライダードライブはベルトさんに依存したクラスであると言えます。

対して仮面ライダーゴーストは変身するときにアイコンをセットするスタイルを取ります。劇中では複数のアイコンを敵と奪い合ったり、敵の特徴によってアイコンを使い分けながら戦うシーンが多く見られます。これをプログラムで表すと以下のような感じになるかと思います。

class 仮面ライダーゴースト{
    protected $core;
 
    public function __construct(アイコン) {
        // 変身するときに外から機能(アイコン)をセットされる
        $this->core = アイコン;
    }
    public function doSomething() {
        return $this->core->doSomething();
    }
    ...
}

ゴーストもアイコンの機能に依存しているのは事実ですが、アイコンがクラスの外から渡されるところがドライブとの相違点です。このように自身の機能(サービス)を外から注入するデザインパターンがDIであり、仮面ライダーゴーストはDIの考え方を導入したライダーであると言えるでしょう。

さらに一歩踏み込んだDIを実現しているゴースト。
繰り返しになりますが、上で示したコード例ではドライブはベルトさんに依存していますし、ゴーストも結局はアイコンに依存しているということになり、両方とも「これが無いと動かない」という状態ではあります。しかしゴーストはさらに一歩踏み込んで、機能そのもの(具象クラス)ではなく型(インターフェース)さえ合っていれば技を使うことができるようになっています。

プログラムで表すと、以下のような形です。

class 仮面ライダーゴースト{
    protected $core;
 
    public function __construct(IconInterface アイコン) {
        $this->core = アイコン;
    }
    public function 変身音を鳴らす() {
        return $this->core->変身音();
    }
    public function ガンガンセイバーで攻撃する() {
        return $this->core->ガンガンセイバー();
    }
    public function 必殺技を使う() {
        return $this->core->オメガドライブ();
    }
    ...
}

interface IconInterface (
    public function 変身音();
    public function ガンガンセイバー();
    public function オメガドライブ();
    ...
}

class オレアイコン implements IconInterface {
    public function 変身音() {
        return '決闘!ズバッと!超剣豪!';
    }
    public function ガンガンセイバー() {
        return ブレードモードで攻撃する;
    }
    public function オメガドライブ() {
        return 紋章のエネルギーを右脚に纏い強力な跳び蹴りを放つ;
    }
    ...
}
class ロビンアイコン implements IconInterface {
    public function 変身音() {
        return 'ハロー!アロー!森で会おう!';
    }
    public function ガンガンセイバー() {
        return アローモードで攻撃する;
    }
    public function オメガドライブ() {
        return 分身を生成して一斉に光矢を放つ;
    }
    ...
}

オレアイコン(主人公自身の能力が込められたアイコン)は強力な飛び蹴りという必殺技を、ロビンアイコン(ロビンフッドがモチーフ)は分身して弓矢を放つという必殺技を持っているのですが、これを共通の型(IconInterface)に嵌めることで、機能を使うゴースト側は「オメガドライブ」を呼べば、それぞれのアイコンが持つ技を繰り出すことができるようになっています。

プログラムの観点で言えば、サービスや機能を利用する側は特定のインターフェースを持ったオブジェクトがありさえすれば動作するということで、たとえば本番ではDBとやりとりする機能を、テストの時だけファイルと読み書きするクラスに差し替えるといったことが容易になります。つまりクラス間の結合度が緩くできるわけですね。

ちなみに
前述の「ゴースト眼魂」はベルトに装着できるほか、ガンガンセイバーやメガウルオウダー、サングラスラッシャーといった別売のおもちゃや、ガンバライジングというアーケードゲームでも使うことができ、ぜんぶ揃えようとするといいお値段になります。しかもだんだんおもちゃのクオリティが下がり気味なのが気になります。 なかなか商売上手ですね。

ご清聴ありがとうございました。

参考
仮面ライダードライブ(Wikipedia)
仮面ライダーゴースト(Wikipedia)
テレビ朝日