対象読者
- プログラミングを初めてオブジェクト指向という言葉が出てきたけどよくわからない人
- オブジェクト指向という言葉を何となく使用している人
オブジェクト指向とは何か?
プログラミングを始めると必ず耳にする言葉があります。それは「オブジェクト指向」。
しかし、調べてみると出てくるのは小難しくて哲学的なポエムばかり。
- オブジェクト同士の相互作用としてシステムの振る舞いを捉え…
- 現実世界をモデリングした…
これでは分かりませんよね。
では何故、こんな説明をするかというと、 「オブジェクト指向」の明確な定義が存在しない ためです。
「オブジェクト指向」という言葉の独り歩き
巷で言われている「オブジェクト指向」は、Javaっぽい文法のことでしかないことがほとんどです。具体的には クラス を使ったプログラミングのことを指します。1「クラス」についての説明は後述します。
「オブジェクト指向」という言葉は”Smalltalk”というプログラミング言語の説明に初めて使われましたが、この忘れられた言語を知っている人はあまりいないでしょう。「Smalltalk」を知っているのはかなりの物知りかベテランプログラマーだけだと思います。
大多数のプログラマーはJavaやC++でオブジェクト指向という言葉を知り、JavaやC++っぽい書き方のことをオブジェクト指向と認識します。そしてJavaやC++のような書き方をオブジェクト指向だと認識した人たちが、後輩プログラマー達に教えている… という構図がIT業界では出来上がっています。
オブジェクト指向が誕生してから時が経つにつれて「オブジェクト指向」は優れたプログラミングに必須の概念であると誤解され、神から授かった天啓のように扱われるようになりました。「これは良くないコードである」という言葉は「オブジェクト指向が出来ていない」という言葉に置き換わり、「これは優れたコードである」という言葉は「オブジェクト指向が出来ている」という言葉に置き換えられます。何だか凄そうに聞こえますね?
しかしながら、オブジェクト指向というのはプログラムを開発する手法の1つにすぎず、オブジェクト指向が出来ていることと良いコードであることはイコールではありません。プログラムを開発する手法としては他に、関数型プログラミングや手続き型プログラミングなどがありますが、どのような手法を選択するかは開発者次第です。オブジェクト指向というのはあくまで道具に過ぎません。
オブジェクト指向の解釈は人それぞれ
Web上の記事や書籍にあふれるオブジェクト指向の説明はあくまでも筆者の解釈でしかありません。もちろん、この記事もあくまで私の解釈です。
オブジェクト指向の定義は人の数だけ存在しますが、「みんなちがって、みんないい」とは残念ながらなりません。人の数だけ解釈があっていいじゃないかと思われるかもしれませんが、そう考えるとひどい目に合う解釈というのが存在するのです。
今回は実際の業務でひどい目にあってきた私が、ひどい目に合うのを避けるための解釈を説明していきます。
クラスとは?
クラスとはデータ構造(クラス内変数など)と処理(関数など)をまとめて扱いやすくしたもののことです。データの型定義を拡張して、付随する処理も簡単に呼び出せるようにしたというそれだけの話です。
クラスそのものは型定義にすぎず、実体を伴っていないのでそのまま使用することは出来ません。ロボットの設計図を書いた紙そのものが歩き出すとか、そんな馬鹿な話はありませんよね?
大抵のプログラミング言語ではvar a = new ClassA();
などと書いて、ClassAという型を持った何かを生成して使用します。この何かというのが オブジェクト や、 ClassAのインスタンス と呼ばれます。
クラス は型定義を拡張してデータ構造と処理をまとめて扱えるようにしたものであるという理解で問題ありません。変に抽象的にとらえたり、現実世界に置き換えようとするとかえって分からなくなります。
オブジェクト指向はこの クラスというパーツを繋ぎ合わせてシステムを構築していく手法 のことです。
オブジェクト指向における三大要素
ここでは、オブジェクト指向で重要な三大要素として以下の要素を挙げます。
文献によっては四大要素だったり違うものを挙げたりしていますが、伝えたいことは大体一緒です。
-
カプセル化
内部に複雑なものを閉じ込め、外部から見たときの挙動をシンプルにすること -
継承
インターフェース(抽象)に対してプログラミングするということ -
ポリモフィズム(多態性)
異なるものを同じ様に扱えること
カプセル化の本質
「内部に複雑なものを閉じ込め、外部から見たときの挙動をシンプルにすること」
プログラミングに限らず、カプセル化というのはモノ作りには必須の要素です。
カプセル化が出来ていると、実装の中身を知らなくても扱うことが出来ます。入力するものと出力されるものさえ分かっていれば誰でも扱えます。カプセル化が出来ていないと、動作機構まで理解していないと扱うことが出来ません。
エレベータを例にとると、2
- カプセル化が出来ている場合
行きたい階数のボタンを押すだけで動く。誰でも扱えて安全。 - カプセル化が出来ていない場合
アクセルとブレーキが搭載され、行きたい階数まで手動で操作する。熟練の業が必要な上に危険!!!。
プログラミングにおけるカプセル化
-
カプセル化が出来ているパターン
クラスや関数の宣言部分だけ読めば何をするのか、どう使うのか分かる -
カプセル化が出来ていないパターン
- 引数によく分からない変数を大量に渡す必要がある
(Win32APIなど) - 中身を読まないと何をするのか分からない
- 関数を呼ぶと、関係なさそうな変数が書き換わる
- 引数によく分からない変数を大量に渡す必要がある
継承の本質
「インターフェース(抽象)に対してプログラミングするということ」
継承元のクラス(or インターフェース)は共通規格を表し、同じクラスを継承している場合、ある程度同じ様に扱うことが出来ます。
継承の目的は、 機能の受け継ぎや重複の排除ではありません 。機能の受け継ぎや重複の排除がしたいだけなら、別の方法(後述)を取りましょう。
継承の本質
AがBを継承する(ClassA extends ClassB)場合、「AはBである」が成立するか確認しましょう
OK: 「新幹線は電車である」
NG: 「鉄はレールである」
親クラスには、どのクラスでも使う基本的な機能を 定義 しておきます。(宣言だけで、実装は書かなくてもいいです )
ポリモフィズムの本質
「異なるものを同じ様に扱えること」
例えば… ガソリンで動く自動車と電気自動車では動作原理が全く異なりますが、アクセルを踏めば同じ様に動きます。何故かと言うと、「乗用車」という共通規格を両者が継承しているからです。
「継承」はポリモフィズムを実現するために使います。
ポリモフィズムを実現するには、2つの方法があります。
- 親クラスに処理を実装する
どの場合でも処理が同じ場合 - 親クラスで宣言し、子クラスで処理を実装
抽象的な意味は同じでも、実際の処理に差異がある場合
何故オブジェクト指向で書くのか?
何故オブジェクト指向で書くのか?という説明に対して、多くの文献ではこう説明します。
- 変更に対して柔軟に対応するため
- 再利用性を高めるため
しかしながら、これを真に受けすぎると結構な確率でひどい目に会います。
私の解釈はこうです。
- シンプルなプログラムを書くため
再利用性って現実には無理だよね
変更に対して柔軟なコードを書きたい場合重要なのは、
- コード量を減らす
- 疎結合にする
(クラス同士の結びつきを弱くする)
ことです。
将来の変更まで完璧に予測して再利用されるクラスをつくるのは現実的には 不可能 であり、無理に再利用すると炎上します。3
現実世界とコンピュータは違う
よくあるオブジェクト指向の説明として、以下のようなものがあります。
- 現実世界はオブジェクト指向でモデリングできる
出来ません。現実世界ではありえない動作がたくさんあります - クラスの継承を生物で例える (Animalクラスを継承するDogクラス、Catクラス等)
コンピュータと生物は全然違います4
継承よりも委譲
「AはBである」(ClassA extends ClassB)が成り立たないが、クラスAの中でクラスBの機能を使いたい場合、有効なのは以下の方法です。
- 委譲
クラスA内で"new ClassB()"して、使いたいメソッドだけ呼び出す方法 - 汎用的な関数に切り出す
両者の処理を、共通化した関数として再定義する方法
まとめ
-
オブジェクト指向の明確な定義は存在しない
-
オブジェクト指向の三大要素
- 「カプセル化」
内部に複雑なものを閉じ込め、外部から見たときの挙動をシンプルにすること - 「継承」
インターフェース(抽象)に対してプログラミングするということ - 「ポリモフィズム(多態性)」
異なるものを同じ様に扱えること
- 「カプセル化」
-
オブジェクト指向のひどい目に合う解釈に注意する
参考文献
- 「オブジェクト指向と10年戦ってわかったこと」 https://qiita.com/tutinoco/items/6952b01e5fc38914ec4e
- 「オブジェクト指向と20年戦ってわかったこと」 https://qiita.com/shibukawa/items/2698b980933367ad93b4
- 「オブジェクト指向と24年くらい戦ってわかったこととか」 https://qiita.com/Air_Hold/items/85c1794f3c42be481f21
- 「オブジェクト指向にdogやanimalを持ち込むと混乱する話」 https://qiita.com/tutinoco/items/8592f3432c5293b52566