Oracleで提供しているドキュメントを参考にJavaでのオブジェクト指向に対する概念を改めて学びます。英語なので翻訳したものを読みます。
何に使うのか?
オブジェクト指向は、概念とかイメージ的な内容を記載している記事が多くあると思いますが、その理由について記載しようと思います。
オブジェクト指向は考え方
色んな言葉で、色んな例を取り上げて説明している記事が多く見られますがつまるところは、「オブジェクト指向の考え方で作るにはどうすれば良いか?」という事が書いてあります。
そして、オブジェクト指向の考え方は下の様な特徴を持っています。
仕様変更に強い
つまりは、クラス別に役割を与えて実装するので、修正した時に周りのプログラムへの影響が少なくなるように作るので一部を修正するだけで良い。もちろんテストをする必要もありますが、これも単体テスト(JUnitなど)で影響が出ない事の確認を取れます。
アプリケーション拡張しやすい
上の仕様変更に強いという特徴から、想像できるかもしれませんが、新たに追加でプログラムの追加、拡張が簡単に、少ない修正で実現出来ます。
なぜなら
役割を分担しているので、それぞれの担当クラスの修正のみで良いからです。
オブジェクトとは
ドキュメントより以下のような説明がありました。(自分なりに要約しています)
実世界のオブジェクトには2つの特性があります。
犬を例にすると、以下のようになります。
- 状態(名前、色、品種、空腹)
- 動作(尾を振る、吠える、(ものなどを)取ってくる)
自転車の場合は以下のようになります。
- 状態(現在のギア、現在のペダルケイデンス、現在の速度)
- 動作(ギアの変更、ペダルケイデンスの変更、ブレーキの適用)
上のような説明があったのですが、次の説明がとても重要だと思います。
今すぐ時間を取って、すぐ近くにある現実のオブジェクトを観察してください。表示される各オブジェクトについて、2つの質問を自問してください、そして結果をノートなどに書きとめてください。
Q1: 「このオブジェクトはどのような状態になりますか?」
Q2: 「このオブジェクトはどのような動作を実行できますか?」実際に、実世界のオブジェクトの複雑さはさまざまであることに気付くでしょう。
デスクトップランプには2つの状態(オンとオフ)と2つの動作(オン、オフ)しかありませんが、デスクトップラジオには追加の状態(オン、オフ、現在の音量、現在のステーション)と動作があります(オン、オフ、音量を上げる、音量を下げる、シーク、スキャン、調整)。
また、一部のオブジェクトには、他のオブジェクトも含まれることに気付くかもしれません。
これらの実際の観察結果はすべて、オブジェクト指向プログラミングの世界に変換されます。
プログラムでいうオブジェクト
オブジェクトは、
- その状態をフィールド(一部のプログラミング言語の変数)に保存
- メソッド(一部のプログラミング言語の関数)を介してその動作を公開します。
メソッドは、オブジェクトの内部状態で動作し、オブジェクト間通信の主要なメカニズムとして機能します。
データカプセル化は「内部状態を隠し、オブジェクトのメソッドを介してすべての対話を実行することを要求する」ということ
オブジェクト指向の利点
モジュール性:オブジェクトのソースコードは、他のオブジェクトのソースコードとは無関係に記述および保守できます。作成したオブジェクトは、システム内で簡単に渡すことができます。
情報の隠蔽:オブジェクトのメソッドとのみ対話することにより、その内部実装の詳細は外の世界から隠されたままになります。
コードの再利用:オブジェクトが既に存在する場合(おそらく別のソフトウェア開発者によって作成されている場合)、プログラムでそのオブジェクトを使用できます。これにより、スペシャリストは複雑なタスク固有のオブジェクトを実装/テスト/デバッグすることができ、それを信頼して独自のコードで実行できます。プラグ可能性とデバッグの容易さ:特定のオブジェクトに問題があることが判明した場合は、アプリケーションからそのオブジェクトを削除し、そのオブジェクトとして別のオブジェクトをプラグインするだけで済みます。これは、現実世界の機械的な問題を修正することに似ています。ボルトが破損した場合は、マシン全体ではなく、ボルトを交換します。
ほぼ引用(要約)したものを記載していますが、自分もその通りだと思います。試しに現実のオブジェクト(もの)をクラスで表現してみるのも面白そうです。
しかし、申し訳ないがここでは自転車とかをクラスで表現しようとすると大変なことになりそうなので別のものを表現したいと思います。
コップをクラスで表現
上のドキュメントにあったように観察して見ます、そして自問自答します。
- どんな状態になりますか?
- どんな動作をしますか?
自分の答えは以下のようになりました。(そのほかにもあると思います。)
<状態>
- 液体が入っている(いない)
- テーブルの上、地面の上などにある
- 壊れた(壊れてない)
- コップの口が上を向いている(下を向いている)
<動作>
- 飲む
- 注ぐ
- 投げる
- ぶつかる
これをクラスで表現すると。。。
コップクラス
状態はフィールド、動作はメソッドなので。。。
public class Cup { // <状態> /** 液体が入っている(いない) */ private boolean inLiquid; /** テーブルの上、地面の上などにある */ private boolean onTable; /** 壊れた(壊れてない) */ private boolean isBroked; /** コップの口が上を向いている(下を向いている) */ private boolean stateNormal; // <動作> /** * 飲む * @param drinked 飲んだ量 */ public void drink(int drinked) { } /** * 注ぐ * @param pour 注いだ量 */ public void pourItUp(int pour) { } /** * 投げる * @param power */ public void throwCup(double power) { } /** * ぶつかる * @param hardness ぶつかったものの硬さ */ public void crashed(double hardness) { } }
細かい部分に関しては突っ込まないでいただきたく思います。
そして、このコードでは、コップの中にある液体の量がわからないので「コップの液体量」というフィールドが必要になります。
このように、クラスを作成していきます。
つまり、ポイントは以下のようになります。
クラス設計のポイント
- 状態(フィールド)を必要な分定義する
- 動作(メソッド)を定義する
シンプルにこんな感じです。そして今後これを使ってアプリケーションを作成するときにいろんな問題が出てきますのでそれを解決する手段を学んでいきたいと思います。
そして、現実にある物をクラスとして表現するのは、設計のための良い練習になると思います。
はっきり言って、答えはありません。作成したクラスが適切かどうか、は使ってみなくてはわかりませんが推測する事は出来ますので、作って動かしてみるのがオブジェクト指向の理解への近道だと思います。
でわでわ。。。