目次
オブジェクト指向プログラミングとは「プログラムの作り方」の一つ
こんにちは。技術チームの岩谷です。最近、とあるかたから「オブジェクト指向プログラミングって何?」という非常にザクっとした質問をいただきました。本連載ではこのことについて説明をしていきたいと考えています。
まず「オブジェクト指向プログラミング(OOP:object-oriented programming)」とは「プログラムの作り方」の一つです。
プログラムを作る際に望まれる事として、
- 効率的に処理したい
- ミスのない処理をしたい
- 作ったものを再利用したい
という事柄が挙げられますが、これらをよりよく実現する方法の一つがOOPなのです。「オブジェクト(=物)って何?」と疑問に思われるかもしれません。ここでは誤解を恐れず直感的にいいます!「オブジェクト=人」だと思ってください。すみません、とりあえず思ってください。「オブジェクト指向プログラミング」とは「やりたい事を人のようにとらえて」プログラムを作っていく方法なのです。「事象を擬人化する」プログラムの作り方だと思ってください。
オブジェクト指向プログラミングをJavaで行う事はできます。でもJavaで作ると必ずオブジェクト指向プログラミングになるわけではありません。
我々が普段プログラムを作成する場合JavaやPython、Rubyなど「プログラミング言語」を使用しますが、これらの言語は「オブジェクト指向機能を持つプログラミング言語」と呼ばれOOPの作り方でプログラムを作成することができます。ここでよくある誤解が「Javaで作ったプログラムは必ずOOPになる」という誤解です。ほんとうは「OOPの作り方をしたプログラミングをJavaで行う事はできる。でもJavaで行ったプログラミングが必ずOOPの作り方になるわけではない」ということです。プログラミング言語はあくまで「道具」です。包丁やお鍋と同じです。切れのいい包丁を使っても盛り付けの綺麗なお刺身ができるとは限らないのと似ています。
今日はそれを説明するために、Javaで作った2つのプログラムソース用意しました。
比較してみよう:OOPと非OOP
以下のプログラムソースコードは、
- オブジェクト指向でプログラミングされているソースの例(OOPの例)
- オブジェクト指向でプログラミングされていないソースの例(非OOPの例)
です。これら2つのサンプルプログラムは同じ機能を持っています。その機能は、
- 社員一人の「社員ID」「社員名」「性別」「今日は出勤している?していない?」という情報を画面に表示する。
- 前提として社員は”ABCDEF”という社員IDを持っている。
という機能です。
まず、オブジェクト指向プログラミングで記述されているソースです。クラス「TestA」を手動で起動すると、クラス「TestA」からクラス「ClassShainA」の処理が呼び出されています。TestAの10行目でオブジェクト指向プログラミングらしく「new」という言葉を使って「社員オブジェクトの作成」を行っています。13行目,16行目,19行目,22行目で社員オブジェクトが持つ情報へアクセスを行って画面にデータを表示しています。
続いて、オブジェクト指向プログラミングで記述されていないソースです。同じくクラス「TestB」を手動で起動すると、クラス「TestB」からクラス「ClassShainB」の処理が呼び出されています。このソースでは上記TestAのような「new」という言葉を使っていません。13行目,16行目,19行目で社員オブジェクトが持つ情報へアクセスを行って画面にデータを表示しています。
注目していただきたいのは、両者のソースにある項目「shainId(ソースの青い部分)」とOOPのソースだけにある項目「shain(ソースの赤い部分)」の比較です。この両者はプログラムの中で「同じような場所」で使用されていることがお分かりいただけると思いますが、この両者の違いを感じていただきたいのです。まず「shainId(ソースの青い部分)」とは何でしょうか?これは「社員ID」という社員一人一人に割り当てられた「ただの文字列」です。対して「shain(ソースの赤い部分)」とは何でしょうか?これは「社員オブジェクト」という「一人の社員そのものを擬人化したオブジェクト」になります。両者の「isShukkin」という関数を見てみてください。OOP(TestA)のソース22は行目、非OOP(TestB)のソースは19行目に書かれています。両者とも「今日、社員は出勤しているか?」という状態を返却する関数ですが、その設計思想は異なります。OOP(TestA)のisShukkin関数は「プログラムの中で擬人化された社員」が「”私”は今日、出勤していますよ/休んでいますよ」と社員自身(=shainオブジェクト)が答えているイメージです。対して非OOP(TestB)のisShukkin関数は「TestBのプログラム」が「社員IDという文字列」をキーに「”その社員IDの社員”は今日、出勤しています/休んでいます」という状態を取得しているイメージです。
ポイント:OOPが共通化したい事柄は何?それは「責任」です。
ここで両者の「isShukkin」関数を見てください。OOPのプログラム(ClassShainA)では23行目、非OOPのプログラム(ClassShainB)では20行目になります。これら「ClassShainA、ClassShainB」は社員のデータを取得する際に「何かを共通化」する事を目的として存在しますが、その共通化したいものは何でしょうか?
OOPのプログラムは「社員という存在を”擬人化”したオブジェクト」を共通化していることになります。対して非OOPのプログラムは「社員IDをキーにした手続きを共通化しているだけ」であることにお気づきいただきたいのです。私はこの違いを「責任」というキーワードで表現できると考えています。社員に各々責任があるように、この社員オブジェクト(ClassShainA)にも責任があります。それは「社員の情報をオブジェクトの生成から消滅まで保持し続けて、呼び出し元からの求めに応じて値を返却する」という責任です。非OOPのプログラムであるClassShainBにはそのような「情報を保持する責任」というものはありません。非OOPのプログラムは単純に「入力パラメータを受け取って出力結果を返す」という手続きの集合体に過ぎないのです。
この「責任」をオブジェクトとして共通化して一元管理できることがOOPと非OOPの大きな違いであると私は考えています。上記の非OOPのプログラムの例では「単なる文字列」に過ぎない「社員ID」と「手続き」に過ぎない「isShukkin関数」が分離してしまっていることで「責任の管理」が複雑になっているのです。本記事の例はプログラムの記述量が少ないので違いはさほど現れませんが、これが巨大なプログラムになればなるほど、OOPの「責任の管理が共通化・一元管理できる」というメリットは大きなものになってきます。
次回は継承について
今回は連載の第一回としてOOPと非OOPの違いを簡単ではありますが説明させていただきました。次回はOOPと密接な関係にあるプログラミング手法「継承」について説明します。