20
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

マサカリAdvent Calendar 2017

Day 21

やはり「オブジェクト指向」の「クラス」を「タイヤキの金型」とかって喩えるのは間違っている。

Last updated at Posted at 2017-12-20

TL;DR

「クラス」と「クラス定義」は区別して説明するべき。
「クラス」とは「分類」である。
『「クラス」とは「分類」』とすることで、「継承」も説明できる。

はじめに

オブジェクト指向の用語の中でも、とかく「クラス」は喩えられがちです。
まずは「クラス」がどのように喩えられているか、よく見かけるものを挙げてみましょう。

  • クラスとは、機械の設計図のようなもの
  • クラスとは、料理のレシピのようなもの
  • クラスとは、タイヤキの金型のようなもの

なるほど。
いずれも、「何かの作り方」が「クラス」であるという喩えです。
そして「何か=インスタンス」という説明になっていることが多いです。

しかし、私はこれらの喩えに敢えて異を唱えます。

『「インスタンスの作り方」が「クラス」である』と喩えるのは間違っている

より正確にいえば、

『「インスタンスの作り方」そのものが「クラス」である』と喩えるのは間違っている

「クラス」と「クラス定義」を使い分けよう

上記のような喩えって、「クラス」の説明ではなく「クラス定義」の説明だと思うんです1
そして、「クラス」と「クラス定義」って、(初心者向けの説明では)もっと慎重に使い分けるべきだと思うんです。

当たり前のことを書くと、

  • 「クラス」とは
    • クラスのこと
  • 「クラス定義」とは
    • 「クラス」の定義のこと

そして、JavaやC#のようなオブジェクト指向言語におけるプログラミングとは、専ら『「クラス定義」をすること』だと言えます。

「クラス」とは「分類」である

では、「クラス」とは一体何なのでしょうか。

「クラス」とは「分類」のことです。そのまんま。
『2年生は3クラスに分かれている』というときの「クラス」と同じです。
また、『ネコは哺乳類に分類される』というときの「分類」は英語で"class"です。
敢えて何かに喩える必要もないと思ってます。

「クラス」を理解する上で大事なのは、上手い喩えよりも

  • 何を、分類しているのか
  • どのように、分類しているのか
  • 何のために、分類しているのか

ということを理解することです。

「分類」されるのはオブジェクト

オブジェクト指向の世界において2、「分類」されているのはオブジェクトです。

この世界では、

このオブジェクトは、どのクラスに属しているのか

ということが非常に重要です。

「分類」のしかた

ここ、ちょっと回りくどい話になります

現実世界の「分類」は、モノありき

現実世界において、「分類」は既存のモノに対してなされることが殆どです。
神が作った(かどうかは分かりませんが)この世界に存在する様々なモノを、我々人類が「分類」してきたのです。

例えば、目の前に「4本足でニャーと鳴く動物」がいたとします。
このとき、我々がそれを『「ネコ」と識別する』ことができるのは、その動物が既にネコとして「分類」されていることを知っているからです3
(あまりにも当たり前すぎて、逆に分かりづらい説明になってるかも。それぐらい当たり前なことをいっています)

先に「分類」を「定義」し、後からその「定義」に従うモノを生み出す

現実世界では、(超クリエイティブなスーパーイノベーター以外は)こんなことはしません。

「オブジェクト指向」の世界の「分類」は、定義ありき

翻って、前述したとおりJavaやC#のようなオブジェクト指向言語におけるプログラミングとは、専ら「クラス定義」です。
つまり、プログラミングとは『ある「分類」の概念や特徴を「定義」している』ことに他なりません。
プログラミングの世界では、いわばプログラマーが神なので、モノを生み出すより先に「分類」を「定義」してしまうのです。

Javaでサンプルを挙げてみましょう。

ネコの概念を「クラス」として定義
// 「ネコ」とは…
public class ネコ {
  // 4本足で、
  int getLegCount() { return 4; }
  // ニャーと鳴く、
  String cry() { return "ニャー"; }
  // 動物である
  boolean isAnimal() { return true; }
}

愚直なコードですが、これが「クラス定義」であることは間違いありません。
ともかく、ネコを分類する「クラス」が定義できました。

では、「ネコに分類されるモノ」を生み出すプログラムを書いてみましょう。
なお、これ以降はプログラム寄りの記述となるため、「モノ」は「オブジェクト」、「生み出すこと」は「生成する」と書くことにします。

ネコに分類されるオブジェクトを生成する
Object x1 = new ネコ();
Object x2 = new ネコ();
Object x3 = new ネコ();

new演算子にクラス名を渡すと、「そのクラスに属するオブジェクト」が生成されます。また、「○○クラスに属するオブジェクト」は、意味的に「○○に分類されるオブジェクト」と言い換えられます。
つまり、このプログラムを実行すると「ネコに分類されるオブジェクト」が3つ生成されることになります。
ちなみに、1つのクラス定義から複数のオブジェクトが生成できるのは、オブジェクト指向言語の特徴の1つです4

「インスタンス」とは

ここで、「インスタンス」という用語について整理しておきましょう。
「インスタンス」とは、『「クラス定義」を基に生成された実体』だと説明されます。

先ほどの例でいえば、「ネコに分類されるオブジェクト」が「ネコインスタンス」となります。また、これを単に「ネコオブジェクト」と呼ぶこともあります。
つまり、以下は全て同じ意味です。(上段2つの呼び方することは滅多にありませんが)

  • ネコに分類されるオブジェクト
  • ネコクラスに属するオブジェクト
  • ネコインスタンス
  • ネコオブジェクト

「分類」のメリット

「分類」することのメリットについては、ここで多くを説明する必要は無いかと思います。
オブジェクトの「分類」によって得られるメリットは、現実世界でモノを「分類」する際と同様だからです。

個々のモノをそのまま扱うのは大変です。
纏まった「分類」をつくることで、効率よく作業をすることができるようになります。

なぜ「タイヤキの金型」ではダメなのか

ここから本題です

ここまでで、以下を説明してきました。

「クラス」と「クラス定義」を使い分ければ、『「クラス」とは「分類」である』と説明できる

では、冒頭で挙げた以下の喩えでは何がダメなのでしょうか。

  • クラスとは、機械の設計図のようなもの
  • クラスとは、料理のレシピのようなもの
  • クラスとは、タイヤキの金型のようなもの

実は、これらの喩えでも「クラス定義」に関しては、問題なく説明することができます。
しかし、これらの喩えでは「オブジェクト指向」のある概念を上手く説明できません。
上手く説明できない概念とは、クラスの「継承」です。

「継承」とは

クラスの「継承」そのものの解説については、バッサリと割愛します。

階層構造と「継承」の説明

「オブジェクト指向」における「継承」の説明では、以下のような階層構造がよく用いられます。

「継承」の説明でよくある階層構造
- 動物
    - イヌ
        - プードル
    - ネコ
        - ミケネコ

先ほど挙げた「ネコのクラス定義」をベースに、階層構造に従うようにコードを少し変更します。

ネコの概念を「クラス」として定義(継承を使用)
// 「動物」とは…
public abstract class 動物 {
  // 「足の数」を取得でき、
  abstract int getLegCount();
  // 「鳴く」ことができる
  abstract String cry();
}

// 「ネコ」とは…「動物」に分類され、
public class ネコ extends 動物 {
  // 4本足で、
  @Override int getLegCount() { return 4; }
  // ニャーと鳴く
  @Override String cry() { return "ニャー"; }
}

まずは、復習をかねて「ネコオブジェクト」の説明をしてみましょう。

  • 「ネコオブジェクト」とは、「ネコのクラス定義」を基に生成されたオブジェクト
    • 「ネコオブジェクト」とは、「ネコクラス」に属したオブジェクト(上記と同義)
    • 「ネコオブジェクト」とは、ネコに分類されるオブジェクト(上記と同義)

次に、「サブクラス」の説明をしてみましょう。

  • 「ネコ」は、「動物」に分類される
    • 「ネコクラス」は、「動物クラス」のサブクラス(上記と同義)
    • 「ネコ」は、「動物」のサブクラス(上記と同義。簡略化した言い方)
  • 「ミケネコ」は、「ネコ」に分類され、必然的に「動物」にも分類される
    • 「ミケネコクラス」は、「ネコクラス」のサブクラスであり、必然的に「動物クラス」のサブクラス(上記と同義)
    • 「ミケネコ」は「ネコ」のサブクラスであり、必然的に「動物」のサブクラス(上記と同義。簡略化した言い方)

さらに、インスタンスの説明をしてみましょう。

  • 「ネコインスタンス」は、「ネコクラス」のインスタンス
    • 「ネコインスタンス」は、「動物クラス」のインスタンス
  • 「ミケネコインスタンス」は、「ミケネコクラス」のインスタンス
    • 「ミケネコインスタンス」は、「ネコクラス」のインスタンス
      • 「ミケネコインスタンス」は、「動物クラス」のインスタンス

『「クラス」とは「分類」である』という説明で、十分に上記の説明がつくことがお分かり頂けるでしょうか。
「クラス」を「タイヤキの金型」で喩えていると、この階層構造の説明ができないのです。

というわけで、最後にもう一度

「クラス」とは「分類」である

補足

「継承」よりも、「特化」と「汎化」

どうも「継承」は、「コードの再利用のため」と説明されがちです。確かに継承がコードの再利用につながることはよくありますが、それは継承の副作用にすぎません。
しかし、初心者が書くコードには「コードの再利用だけを目的とした、誤った継承5」が出てくることがあります。
これは、上記のような説明が一因ではないでしょうか。

そこで、「継承」よりも、「特化」と「汎化」を強調したいです。
一応、書いておくと、

  • 特化
    • 動物 →(特化)→ ネコ →(特化)→ ミケネコ
  • 汎化
    • 動物 ←(汎化)← ネコ ←(汎化)← ミケネコ

ですね。

「特化」と「汎化」でextendsを説明すれば、「再利用のための継承」のような誤解は生じにくくなるのではないでしょうか。

おわりに

調子に乗って、2本目のマサカリです。
1本目はこちら→やはり「オブジェクト指向」のオブジェクトを「モノ」とかって訳すのは間違っている。

もっとコンパクトな記事を書けるように精進したいです。

  1. 説明している側としては、それが「クラス定義」のことと理解していつつも「クラス」と書いてしまっているのだと想像されます

  2. ちゃんというと、「クラスベースのオブジェクト指向プログラムの世界」において

  3. そもそも「足」や「動物」の概念も、定義による分類に過ぎないですね

  4. 「マルチプルインスタンス」という。本投稿では説明しません

  5. 『支出 extends 収入』のような、is-a関係とならない継承

20
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?