オブジェクト指向の概念 〜OracleDocのチュートリアル1〜

Oracleで提供しているドキュメントを参考にJavaでのオブジェクト指向に対する概念を改めて学びます。英語なので翻訳した読みます。

オブジェクトとは

ドキュメントより以下のような説明がありました。(自分なりに要約しています)

実世界のオブジェクトには2つの特性があります。
犬を例にすると、以下のようになります。

  1. 状態(名前、色、品種、空腹)
  2. 動作(尾を振る、吠える、(ものなどを)取ってくる)

自転車の場合は以下のようになります。

  1. 状態(現在のギア、現在のペダルケイデンス、現在の速度)
  2. 動作(ギアの変更、ペダルケイデンスの変更、ブレーキの適用)

上のような説明があったのですが、次の説明がとても重要だと思います。

今すぐ時間を取って、すぐ近くにある現実のオブジェクトを観察してください。表示される各オブジェクトについて、2つの質問を自問してください、そして結果をノートなどに書きとめてください。
Q1: 「このオブジェクトはどのような状態になりますか?」
Q2: 「このオブジェクトはどのような動作を実行できますか?」

実際に、実世界のオブジェクトの複雑さはさまざまであることに気付くでしょう。
デスクトップランプには2つの状態(オンとオフ)と2つの動作(オン、オフ)しかありませんが、デスクトップラジオには追加の状態(オン、オフ、現在の音量、現在のステーション)と動作があります(オン、オフ、音量を上げる、音量を下げる、シーク、スキャン、調整)。
また、一部のオブジェクトには、他のオブジェクトも含まれることに気付くかもしれません。
これらの実際の観察結果はすべて、オブジェクト指向プログラミングの世界に変換されます。

プログラムでいうオブジェクト

オブジェクトは、

  1. その状態をフィールド(一部のプログラミング言語の変数)に保存
  2. メソッド(一部のプログラミング言語の関数)を介してその動作を公開します。

メソッドは、オブジェクトの内部状態で動作し、オブジェクト間通信の主要なメカニズムとして機能します。
データカプセル化は「内部状態を隠し、オブジェクトのメソッドを介してすべての対話を実行することを要求する」ということ

オブジェクト指向の利点

モジュール性:オブジェクトのソースコードは、他のオブジェクトのソースコードとは無関係に記述および保守できます。作成したオブジェクトは、システム内で簡単に渡すことができます。

情報の隠蔽:オブジェクトのメソッドとのみ対話することにより、その内部実装の詳細は外の世界から隠されたままになります。
コードの再利用:オブジェクトが既に存在する場合(おそらく別のソフトウェア開発者によって作成されている場合)、プログラムでそのオブジェクトを使用できます。これにより、スペシャリストは複雑なタスク固有のオブジェクトを実装/テスト/デバッグすることができ、それを信頼して独自のコードで実行できます。

プラグ可能性とデバッグの容易さ:特定のオブジェクトに問題があることが判明した場合は、アプリケーションからそのオブジェクトを削除し、そのオブジェクトとして別のオブジェクトをプラグインするだけで済みます。これは、現実世界の機械的な問題を修正することに似ています。ボルトが破損した場合は、マシン全体ではなく、ボルトを交換します。

ほぼ引用(要約)したものを記載していますが、自分もその通りだと思います。試しに現実のオブジェクト(もの)をクラスで表現してみるのも面白そうです。
しかし、申し訳ないがここでは自転車とかをクラスで表現しようとすると大変なことになりそうなので別のものを表現したいと思います。

コップをクラスで表現

上のドキュメントにあったように観察して見ます、そして自問自答します。

  1. どんな状態になりますか?
  2. どんな動作をしますか?

自分の答えは以下のようになりました。(そのほかにもあると思います。)
<状態>

  1. 液体が入っている(いない)
  2. テーブルの上、地面の上などにある
  3. 壊れた(壊れてない)
  4. コップの口が上を向いている(下を向いている)

<動作>

  1. 飲む
  2. 注ぐ
  3. 投げる
  4. ぶつかる

これをクラスで表現すると。。。

コップクラス

状態はフィールド、動作はメソッドなので。。。

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) {
    }
}

細かい部分に関しては突っ込まないでいただきたく思います。
そして、このコードでは、コップの中にある液体の量がわからないので「コップの液体量」というフィールドが必要になります。

このように、クラスを作成していきます。
つまり、ポイントは以下のようになります。

クラス設計のポイント

  1. 状態(フィールド)を必要な分定義する
  2. 動作(メソッド)を定義する

シンプルにこんな感じです。そして今後これを使ってアプリケーションを作成するときにいろんな問題が出てきますのでそれを解決する手段を学んでいきたいと思います。

でわでわ。。。