57-ポリモーフィズムの利用機会を見逃さない

プログラマが知るべき97のこと」の57個目のエピソードは、ポリモーフィズムに関する話です。ポリモーフィズムオブジェクト指向プログラミングにおいて最も重要な概念の1つです。日本語で多態性と呼ばれるこの技術は、実装レベルで考えれば方が同じで振る舞いが異なるクラスを定義できるということです。その事による恩恵としては、冗長なif文を減らすことができる事でしょう。例えば次のようなif文を含むメソッドがあるとします。

class Controller {
  void run(Request req) {
     if (req.isGet()) {
        // GETの場合の処理
     } else if (req.isPost()) {
        // POSTの場合の処理
     } else {
       throw new AssersionErrror();
     }
  }
}
class Client {
  void invoke(Request req) {
    Controller controller = new Controller();
    controller.run(req);
  }
}

このクラスはHTTPのリクエストを処理するクラスですが、GETとPOSTを判別して別の処理を実行しています。次のようなポリモーフィズムを利用したコードでは、POSTまたはGETの場合に呼び出されるという前提でロジックを書く事ができます。

abstract class Controller {
  void run(Request req);
}
class GetController extends Controller {
  void run(Request req) {
    // GETの場合の処理
  }
}
class PostController extends Controller {
  void run(Request req) {
     // POSTの場合の処理
  }
}
class Client {
  void invoke(Request req) {
    Controller controller = createController(req);
    controller.run(req);
  }

  Controller createController(Request req) {
     if (req.isGet()) {
        return new GetController();
     } else if (req.isPost()) {
        return new PostController();
     } else {
       throw new AssersionErrror();
     }
  }
}

ポリモーフィズムを使う事で、クライアントのコードはControllerの実装がPOST用なのかGET用なのかを意識しないコードになりました。しかし、if文が全くなくなったというわけではありません。createControllerのメソッドの実装にifが移動しているだけです。
勿論、リフレクションなどの動的な生成方法を使う事でif文を完全に排除することもできますが、分岐そのものがなくなるわけではないことに注意すべきです。また、コード量だけを考えれば、ポリモーフィズムを使わない方がコード量・クラス数も少ないでしょう。こうなってくると、本当にポリモーフィズムは有効なテクニックなのか怪しくなってきました。「未来へのメッセージ」にもあるように、難しいソリューションを使う事で何となく凄い事をしていると錯覚しているのかと思えてきます。
実は、ポリモーフィズムを使ったコードの最大のメリットは単純に条件分岐が減る事ではありません。条件分岐を行う場所をメインの処理から切り離すことができることなのです。上記の例では、リクエストがPOSTとGETで処理を分岐していましたが、それがメインのロジックの中に分散してしまうと、非常に読みにくいコードになります。1本の主シナリオを記述しているのではなく、幾つかの主シナリオが混在する状況です。一方で、それぞれのControllerを作成した場合、それぞれのロジックは完全に分けて考える事ができるのです。分岐部分は別のレイヤーで行い、一旦GET/POSTと判定されたならばそのコンテキストで処理が行われます。だから読みやすいコードとなるのです。読みやすさに対してコストと複雑性を払う意味はあるのです。
とはいえ、ポリモーフィズムも麻疹のようなもので、何でもかんでもポリモーフィズムを使いたくなる時期は誰にでもあります。しかし、ちょっとやりすぎたかな?という経験が、どの程度でセーブすれば最適化という経験に繋がるので、怖がる必要はありません。多少無理して使ってみようと検討することは重要な事です。ただし、流行病なので治す事を忘れずに。

プログラマが知るべき97のこと

プログラマが知るべき97のこと