07 Dec 2014, 11:32

Java におけるポリモーフィズムの整理

はじめに

Haskell で型クラスというものを勉強した.

その延長で, 今までとてもいい加減に理解していた Java のポリモーフィズムについて再度復習した.

なんか, 用語の関係性をすごく曖昧に理解していた気がした.

Polymophism: 多相性

各要素 (定数, 変数, 式, オブジェクト, 関数, メソッドなど) についてそれらが複数の型に属することを許すという性質.

同種のクラスをカテゴリに分類してまとめ, 基本的な動作・設計部分を統一することで, オブジェクトインスタンスの扱いに柔軟性と規律を持たせるための機能.

多相性は 3 つに分類できる.

  • アドホック多相:
  • パラメータ多相:
  • サブタイプ多相:

たとえば Java だと以下に相当する.

  • アドホック多相: オーバーロード
  • パラメータ多相: ジェネリクス
  • サブタイプ多相: 継承, インタフェース

参考:

Polymorphic Type: 多相型

<div class="outline-text-3" id="text-unnumbered-3">
  <p>
    データ構造のコンテナ.
  </p>

  <p>
    データ形式に依存しないコンピュータプログラミング方式をジェネリクス プログラミングという.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AA%E3%83%83%E3%82%AF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0">ジェネリックプログラミング &#8211; Wikipedia</a>
    </li>
  </ul>
</div>

アドホック多相

オブジェクト指向におけるアドホック多相とは, オーバーロードに相当する. 多重定義ともいう.

パラメータ多相

型変数

<div class="outline-text-3" id="text-unnumbered-6">
  <p>
    多相型は宣言されたクラス, 関数に対して, 利用時に具体的な型を与える. これを型変数 (Type variable) という.
  </p>

  <p>
    Java の名前つけルールがあるらしい.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://java.keicode.com/lang/generics-naming.php">名前付けルール &#8211; Java 入門</a>
    </li>
  </ul>
</div>

Generic Type: 総称型

<div class="outline-text-3" id="text-unnumbered-7">
  <p>
    型付けされたプログラミング言語において データ型の定義とそれを参照する式 (型式) の一部にパラメタを許すことによって 類似した構造を持つ複数のデータ型を一括して定義して, それらを選択利用する仕組み.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/%E7%B7%8F%E7%A7%B0%E5%9E%8B">総称型 &#8211; Wikipedia</a>
    </li>
  </ul>

  <p>
    オーバーロード (overload), 継承 (inheritance) と並んでプログラミング言語において ポリモーフィズムを実現するための一つの手段.
  </p>
</div>

言語ごとの実現方法

<div class="outline-text-3" id="text-unnumbered-8">
  <ul class="org-ul">
    <li>
      Java: ジェネリクス, ワイルドカード <ul class="org-ul">
        <li>
          <a href="http://futurismo.biz/archives/2750">Java でのジェネリックスの使い方まとめ | Futurismo</a>
        </li>
      </ul>
    </li>

    <li>
      C++: テンプレート
    </li>
    <li>
      Haskell: <ul class="org-ul">
        <li>
          リスト
        </li>
        <li>
          タプル
        </li>
        <li>
          Either
        </li>
        <li>
          Maybe
        </li>
      </ul>
    </li>
  </ul>
</div>

Subtyping: 派生型

データ型 S が他のデータ型 T と is-a 関係にあるとき, S を T の派生型 (はせいがた, subtype) であるという.

基本型のデータを処理するように作られたプログラムは, その派生型のデータでも正しく処理することができる.

基本型-派生型関係ではリスコフの置換原則 (Liskov Substitution Principle) が成り立つ.

2 つの方法がある

  • インタフェース: 型をグループで分類
  • 継承: 型を階層構造で分類

inheritance: 継承

<div class="outline-text-3" id="text-unnumbered-10">
  <p>
    ほとんどのクラスベースオブジェクト指向言語では, サブクラス (インヘリタンス) が派生型の概念を実現している.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/%E7%B6%99%E6%89%BF_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)">継承 (プログラミング) &#8211; Wikipedia</a>
    </li>
  </ul>
</div>

override: オーバーライド

<div class="outline-text-3" id="text-unnumbered-11">
  <p>
    オブジェクト指向プログラミングにおいてオーバーライド (override) とは, スーパークラスで定義されたメソッドをサブクラスで定義しなおし, 動作を上書きすること.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://ja.wikipedia.org/wiki/%E3%82%AA%E3%83%BC%E3%83%90%E3%83%BC%E3%83%A9%E3%82%A4%E3%83%89">オーバーライド &#8211; Wikipedia</a>
    </li>
  </ul>
</div>

interface: インタフェース

<div class="outline-text-3" id="text-unnumbered-12">
  <p>
    抽象データ型のメソッド.
  </p>

  <p>
    Object 型を分類し, 同じカテゴリに属するクラスに共通のインターフェイスを取り決める.
  </p>

  <p>
    implements ステートメントは, クラスたちのカテゴリ分類を明確にする方法.
  </p>

  <p>
    変数の型としてカテゴリクラスを指定すると, そのカテゴリを Implements したクラス (つまり, カテゴリに属するクラス) のインスタンスも格納できるようになる.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://homepage1.nifty.com/CavalierLab/lab/vb/clsmdl/polymorphism_02.html">ポリモーフィズムとインターフェイス</a>
    </li>
  </ul>

  <p>
    オブジェクトが, 共通のインターフェイスを実装している場合, 他のオブジェクトに置き換えることができる.
  </p>
</div>

<div id="outline-container-unnumbered-13" class="outline-4">
  <h4 id="unnumbered-13">
    どう分類するか?: 共通性/ 可変性 分析法
  </h4>

  <div class="outline-text-4" id="text-unnumbered-13">
    <p>
      オブジェクト指向のこころより引用.
    </p>

    <ul class="org-ul">
      <li>
        共通性分析:時間が経っても変化しにくい構造を見つけるもの
      </li>
    </ul>

    <p>
      共通性分析によってまとめられた概念を抽象クラスによって表現
    </p>

    <ul class="org-ul">
      <li>
        可変性分析:変化しやすい構造を洗い出すもの
      </li>
    </ul>

    <p>
      可変性分析で得た流動的要素は抽象クラスの派生クラスによって実装される
    </p>

    <p>
      設計手順:
    </p>

    <ul class="org-ul">
      <li>
        (抽象クラス) このクラスが持つ責務をすべて全うするにはどうようなインターフェイスが必要か?
      </li>
      <li>
        (派生クラス) この特定実装の中でどうのようにして与えられた仕様を実装できるのか?
      </li>
      <li>
        共通性: 時がたっても変わらないものを抽象クラスに
      </li>
      <li>
        可変性: 流動的要素を具象クラスに.
      </li>
    </ul>

    <p>
      クラスの集合がもつすべての責務を真っ当するために, インタフェースを用意する.
    </p>

    <p>
      Jim Coplien が提唱. p235 第 15 章から抜粋.
    </p>

    <ul class="org-ul">
      <li>
        <a href="http://www.amazon.co.jp/%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E3%81%A8%E3%81%A8%E3%82%82%E3%81%AB%E5%AD%A6%E3%81%B6%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%AE%E3%81%93%E3%81%93%E3%82%8D-Software-patterns-%E3%82%A2%E3%83%A9%E3%83%B3%E3%83%BB%E3%82%B7%E3%83%A3%E3%83%AD%E3%82%A6%E3%82%A7%E3%82%A4/dp/4894716844">Amazon.co.jp: デザインパターンとともに学ぶオブジェクト指向のこころ (Software patterns series): アラン・シャロウェイ, ジェームズ・ R ・トロット, 村上 雅章: 本</a>
      </li>
    </ul>
  </div>
</div>

型クラス

<div class="outline-text-3" id="text-unnumbered-14">
  <p>
    Haskell の概念.
  </p>

  <ol class="org-ol">
    <li>
      型は値をグループ化する.
    </li>
    <li>
      型クラスは, 型をグループ化する.
    </li>
  </ol>

  <p>
    この説明はわかりやすい.
  </p>

  <ul class="org-ul">
    <li>
      値 < 型 < 型クラス
    </li>
    <li>
      <a href="http://jutememo.blogspot.jp/2009/05/haskell.html">Haskell のモジュールの階層化と, 型クラス &#8211; パラメータ多相とアドホック多相 | すぐに忘れる脳みそのためのメモ</a>
    </li>
  </ul>

  <p>
    型を分類する点でいえば, Java のインタフェースと同義.
  </p>
</div>

おわりに

先月くらいにクラス設計をしていたときに, 会社である怖い人が,

継承とは, オブジェクトを分類するための手段なんだ!

といっていたが, ようやくその意味を理解した気がした.