オブジェクト指向の概念5〜パッケージとは〜

オブジェクト指向の概念というテーマでこの記事を記載しています。今夏は「パッケージ」について記載します。
参考にするサイトはOracleのドキュメントページです。

パッケージ

パッケージは、関連するクラスとインターフェイスのセットを整理する名前空間です。
概念的には、パッケージはコンピューター上の異なるフォルダーに似ていると考えることができます。
HTMLページを1つのフォルダーに、画像を別のフォルダーに、
スクリプトまたはアプリケーションをさらに別のフォルダーに保存することができます。
Javaプログラミング言語で書かれたソフトウェアは、数百または数千の個別のクラスで構成されている可能性があるため、関連するクラスとインターフェースをパッケージに入れて整理することは理にかなっています。

という記載があるのですが、早い話が「ソースは整理して配置しましょう」ということです。
理由は「作成したコードは何度でも利用したいから」です。
整理しないと何がどこにあるかわからなくなりますから(笑)

ポイント

ソースの量は作成するアプリにより変わりますが、何かのアプリを作成するときには「ライブラリ」を使用したり「フレームワーク」を使用したりすると思います。どちらも大差ありませんが「共通部品」(commonパッケージ)と「処理部品」(それぞれの機能の処理部品)と分かれている方が使いやすいです。

パッケージングの例

例えば、HTMLで入力コンポーネントを作成し、計算をサーバー側でやる(簡単な計算はjSでできますが。。。)場合は

  1. HTMLで入力したものをサーバーにリクエストという形でサーバーに送信します。
  2. サーバーで受け取った後に入力値を取得して計算結果を返す(レスポンス)

というような実装をするとします。

その場合は、以下のようなパッケージングが可能です。というかサンプルとして使えます。

共通部品:

  1. HTMLからの入力を受け取る処理と返却する処理(リクエストとレスポンスを処理する部品)
  2. 計算の種類別の計算処理用の部品(必要なものをそれぞれの部品で呼び出せば良い)

それぞれの処理部品:
画面からの入力で足し算を行うケース

1.共通部品で入力値A, Bを取得
2.AとBの値をどのように計算するかそれぞれの部品で指定(処理)する
3.上の値を共通部品の「足し算」部品で計算
4.計算結果を共通部品「レスポンス処理」で返却

大まかに上記のような形で実装することができます。
このように、パッケージングをしておくと共通部品とそれぞれの処理を行う部品の区別が簡単にできるのでソースが整理されるし、他のプログラマが見たときにも実装しやすいはずです。

簡単ですが、このような考え方でパッケージングを行うと大きなものを作ろうとしたときに便利です。

Javaのみのアプリ

もう一つサンプルとしてのパッケージングを紹介したいと思います。

それは、Javaのみで作成するアプリケーションのパッケージングです。

具体的には、テキストRPG(戦闘シーンのみ)を作成した時のものを紹介したいと思います。

ものはこちらになります。

パッケージの根元には、自分が作成するアプリケーションであるという意味で「jp.zenryokuservice」という名前をつけています。

引き続き、テキストRPGなので「rpg」と付けて、登場するキャラクター、アイテム、シーン(戦闘シーン以外にも作成する予定です。)ユーティリティとパッケージを分けています。

rpgパッケージの直下には、ゲームを起動するためのメインメソッドと、マルチスレッド処理の為のゲームクラス、ロジッククラスと分けて作成しています。

とても単純なもので、複雑にならない様にするのが一番だと思います。

でわでわ。。。



オブジェクト指向の概念4〜インターフェースとは〜

インターフェースについて学習します。
参考サイトはここのページがメニューになっていて、「What Is an Interface?

余談

最近は、すっかり忘れていたのですが年末が近づき、記載したものを見直していたところ。。。中途半端な記事を見つけたので、キリよく締める方向に向かっていこうと考えています。

インターフェースとは

既に学んだように、オブジェクトは公開するメソッドを介して外界との相互作用を定義します。メソッドは、外界とのオブジェクトのインターフェースを形成します。たとえば、テレビの前面にあるボタンは、プラスチックケースの反対側にある電気配線とユーザーとの間のインターフェイスです。「電源」ボタンを押して、テレビのオンとオフを切り替えます。
最も一般的な形式では、インターフェイスは空のボディを持つ関連メソッドのグループです。自転車の動作は、インターフェイスとして指定されている場合、次のように表示されます。

<インターフェース>

interface Bicycle {

    //  wheel revolutions per minute
    void changeCadence(int newValue);

    void changeGear(int newValue);

    void speedUp(int increment);

    void applyBrakes(int decrement);
}

このインターフェイスを実装するには、クラスの名前が(たとえばのような特定の自転車ブランドに)変更され、クラス宣言でキーワードをACMEBicycle使用しますimplements。

<実装クラス>

class ACMEBicycle implements Bicycle {

    int cadence = 0;
    int speed = 0;
    int gear = 1;

   // The compiler will now require that methods
   // changeCadence, changeGear, speedUp, and applyBrakes
   // all be implemented. Compilation will fail if those
   // methods are missing from this class.

    void changeCadence(int newValue) {
         cadence = newValue;
    }

    void changeGear(int newValue) {
         gear = newValue;
    }

    void speedUp(int increment) {
         speed = speed + increment;   
    }

    void applyBrakes(int decrement) {
         speed = speed - decrement;
    }

    void printStates() {
         System.out.println("cadence:" +
             cadence + " speed:" + 
             speed + " gear:" + gear);
    }
}

インターフェースには以下のメソッドが定義されています。

1.changeCadence
2.changeGear
3.speedUp
4.applyBrakes

これらのメソッドを実装するクラスACMEBicycleでは上記のメソッドをオーバーライドして、書の中身を実装します。

こうする事で、インターフェースを実装するクラスが複数ある場合には、ACMEBicycle以外にもxxBicycleの様に色々なクラスを作成でき、インターフェースに定義しているメソッドを呼び出す事が出来ます。

つまりは、中身の違う処理(メソッド)を1つのメソッド呼び出しで実行する事が出来ます。下にコマンドインターフェース(自作のインターフェース)を実装した時の記事リンクをつけておきます

Java OpenCV 〜背景除去、輪郭を学習する準備4:コマンドで起動する実装〜

早い話が。。。

インターフェースを実装するクラスは、インターフェースにあるメソッド(抽象メソッド)をオーバーライドすることが強制されるので、必ず対象のメソッドがあると言う意味になります。

つまり、ここの記事に記載したようにcode>@Overrideアノテーションをつけて「オーバーライドしていますよ!」と明示的に示すこともできますし、インターフェースを実装したコマンドクラスを作成していろんなコマンド処理を実装することもできます。
上のコマンド処理に関してはDiscordアプリを作成した時に実装したものです。よく使う技術なのでサンプルに作成しました。

まとめると

インターフェースを実装(implements)下クラスは指定のメソッドを持っているので、複数の「XXX」メソッドを一行で呼び出すことができると言うことです。
詳細に関しては、上の「インターフェースを実装したコマンドクラスを作成」の記事に記載しています。

でわでわ。。。



関連ページ

  1. Java インターフェース 〜Listの使い方、ワンポイントレッスン的な〜
  2. Java インターフェース〜Mapの使い方 ワンポイントレッスン的な〜
  3. Java Basic インターフェース 〜Step2_3 〜

オブジェクト指向の概念3〜継承とは〜

オラクルのチュートリアルを読んで「継承」に関して理解を深めます。
英語なので翻訳して読みました。
ここでいう「継承」とは下のような書き方でクラスの継承を行うときに出てくる言葉です。下にソースを示します。

public MyClass extends ParentClass {
   /** フィールド */
   private int myNo;
   /** コンストラクタ */
   public MyClass() {
   }
}

「ParentClass」が親クラス(スーパークラス)です。そして「MyClass」が子クラス(サブクラス)になります。このような関係のことを「継承」と呼びます。

補足

そしてSpring, Playなどのフレームワークを作ろうとしたときにこの「継承」は必須の技術となり、オリジナルの仕組み(フレームワーク)を作る時の基礎になります。

自転車の例

自転車をクラスとして表現した場合に、マウンテンバイクや、ママチャリ、三輪車etcはどのようになるの?という疑問が出ます。それは下のような関係図を作ることができます。

マウンテンバイクなどは「自転車」のカテゴリに属するものです。なので上のような関係図を作りました。
この「関係図」はイメージでも良いです。
そして、この関係をクラスで表現すると下のようになります。

自転車(単純化したもの)

自転車をクラスで表現するために「仕様」を決めます。

  1. 以下の状態(パラメータ)がある
    ・移動スピード
    ・頑丈さ
    ・重さ
  2. 同様に以下の動作を行う
    ・走る
    ・止まる
    ・飛ぶ(空中にいる)

そして、コードで書くと、大まかに下のようになります。
<自転車クラス>

class Bicycle {
   protected double speed;
   protected int toughNess;
   protected double weight;

   public void run() {
   }
   public void stop(){
   }
   private void jump() {
   }
}

<マウンテンバイク>

class MountainByke extends Bicycle {
   /** ギアの数 */
   private int gears;
   /** タイヤのタイプ */
   private int type;

   /** ウィリー */
   public void Welyee() {
   }
}

このようにコードを書くことができます。
この場合、マウンテンバイクは自転車のフィールドを参照することができ。run(), stop()を参照することができます。つまりマウンテンバイククラスの中に左のメソッドを作らなくても使用する事が可能という事です。
ちなみに、「jump()」は「private」なので参照することができません。フィールドも「private」「protected」「public」の修飾子で参照の可否が決まってきます。

「private」クラスの中だけ参照可能

「protected」クラスの継承関係内で参照可能

「public」何処からでも参照可能

まとめ

  1. 親クラス('スーパークラス)と子クラス(サブクラス)の関係を作ることで、複数作るクラスのコードを減らすことができる。
  2. 親クラスを作ることで、サブクラスをカテゴリ分けすることができる
  3. 親クラスの実装は子クラスで使用でき、改めて実装する必要はない、書き換えたいときだけ「オーバーライド」してやる
    こんな感じで、クラスの継承関係を使用して少ないコードで大きなものを作れます。
    そして、オリジナルフレームワークを作ることも可能です。
    さらに、「インターフェース」への理解もあれば、オリジナル・ディペンデンシー・インジェクションも作れそうです。

でわでわ。。。



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

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

何に使うのか?

オブジェクト指向は、概念とかイメージ的な内容を記載している記事が多くあると思いますが、その理由について記載しようと思います。

オブジェクト指向は考え方

色んな言葉で、色んな例を取り上げて説明している記事が多く見られますがつまるところは、「オブジェクト指向の考え方で作るにはどうすれば良いか?」という事が書いてあります。

そして、オブジェクト指向の考え方は下の様な特徴を持っています。

仕様変更に強い

つまりは、クラス別に役割を与えて実装するので、修正した時に周りのプログラムへの影響が少なくなるように作るので一部を修正するだけで良い。もちろんテストをする必要もありますが、これも単体テスト(JUnitなど)で影響が出ない事の確認を取れます。

アプリケーション拡張しやすい

上の仕様変更に強いという特徴から、想像できるかもしれませんが、新たに追加でプログラムの追加、拡張が簡単に、少ない修正で実現出来ます。

なぜなら

役割を分担しているので、それぞれの担当クラスの修正のみで良いからです。

オブジェクトとは

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

実世界のオブジェクトには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. 動作(メソッド)を定義する

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

そして、現実にある物をクラスとして表現するのは、設計のための良い練習になると思います。

はっきり言って、答えはありません。作成したクラスが適切かどうか、は使ってみなくてはわかりませんが推測する事は出来ますので、作って動かしてみるのがオブジェクト指向の理解への近道だと思います。

でわでわ。。。



オブジェクト指向の概念2〜クラスとは〜

今回はOracle Docのこのページを参考にします。日本語訳して読みます。

目的

Oracle Docを読んで、Javaの概要を理解しようという意図の記事です。

クラスとは

クラスは、オブジェクトが作成されるブループリントまたはプロトタイプです。

このセクションでは、実世界のオブジェクトの状態と動作をモデル化するクラスを定義します。

意図的に基本に焦点を当て、単純なクラスでも状態と動作をきれいにモデル化できることを示します。

詳細な説明

現実の世界では、多くの場合、すべて同じ種類の個々のオブジェクトが多数見つかります。
他にも何千もの自転車が存在し、それらはすべて同じメーカーとモデルです。
各自転車は同じ設計図から構築されているため、同じコンポーネントが含まれています。
オブジェクト指向の用語では、自転車は自転車と呼ばれるオブジェクトのクラスのインスタンスであると言います。

例として以下のような自転車クラスのコードを出していました。

つまりは、自転車をクラスで表現すると下の様になる。という事です。

しかし、現実の自転車はもっと複雑です。一部の特徴を抜粋して自転車を表現しています。

下のクラスには、以下の属性(フィールド変数)と振る舞い(メソッド)が定義されています。

  • タイヤの回転数
  • 自転車のスピード
  • ギア
  • それぞれの値を変更する振る舞い
  • 自転車の状態を表現する振る舞い
class Bicycle {

    int cadence = 0;
    int speed = 0;
    int gear = 1;

    void changeCadence(int newValue) {
         cadence = newValue;
    }

    void changeGear(int newValue) {
         gear = newValue;
    }

    void speedUp(int increment) {
         speed = speed + increment;   
    }

    void applyBrakes(int decrement) {
         speed = speed - decrement;
    }

    void printStates() {
         System.out.println("cadence:" +
             cadence + " speed:" + 
             speed + " gear:" + gear);
    }
}

ちなみに、メソッドの前に「public」がないのでメソッド(フィールドも)のスコープはpackageスコープになります。

Javaプログラミング言語の構文は新しく見えますが、このクラスの設計は自転車オブジェクトの以前の議論に基づいています。フィールドcadence、speedおよびgearオブジェクトの状態を表し、およびメソッド(changeCadence、changeGear、speedUpなど)が外の世界との相互作用を定義します。

Bicycleクラスにmainメソッドが含まれていないことに気づいたかもしれません。それは完全なアプリケーションではないからです。アプリケーションで使用される可能性のある自転車の青写真にすぎません。新しいBicycleオブジェクトを作成して使用する責任は、アプリケーションの他のクラスに属します。

そして、自転車クラスを呼び出すクラスが以下になります。
予想の通り、メインメソッドを持っています。

class BicycleDemo { 
    public static void main(String [] args){ 

        // 2つの異なる
        //自転車オブジェクトを作成
        Bicycle bike1 = new Bicycle(); 
        Bicycle bike2 = new Bicycle(); 

        // 
        //これらのオブジェクトでメソッドを呼び出します
        bike1.changeCadence(50); 
        bike1.speedUp(10); 
        bike1.changeGear(2); 
        bike1.printStates(); 

        bike2.changeCadence(50); 
        bike2.speedUp(10); 
        bike2.changeGear(2); 
        bike2.changeCadence(40); 
        bike2.speedUp(10); 
        bike2.changeGear(3); 
        bike2.printStates(); 
    }
}

考える

上の説明にある「自転車クラス」は、実際の自転車としては足りない部分があると思いますが、「何をするためのクラスか?」という疑問を解決していけば自ずと適切なクラス設計ができると思います。

クラスは

設計図のようなもので、このクラスを元に「オブジェクト(やインスタンス)」を作成しそれを使用して様々なこと(処理)を行うための部品(オブジェクト)です。

上のように自分は理解しました。なかなかに理解がしやすい内容でした。(自分にとっては)

いまいち。。。だった人は、メインメソッドをよくみてみてください。

メインメソッドの説明

上で示されたメインメソッドは以下のようなことをしています。

  1. 自転車を2台用意(インスタンス化)する
  2. 自転車の1台目に「ケーデンス」を50に設定する
  3. スピードを10加算する
  4. 1台目の状態を表示する
  5. 2台目も同様に(コード参照)設定し、状態を表示する

こんな感じです。

あとは、写経するとか実際に作って動かしてみて自分なりに理解するしかありません。
オススメする方法はやはり「写経すること」です。以下のような感じです。

  1. 写経して
  2. 動かして
  3. パラメータなどを変えてみて
  4. 新しいメソッドを追加してみて
  5. 改めてオリジナルのクラスを作成してみる(動かす)

こんな感じでやってみると「お?」とインスピレーションが舞い降りてきます(理解できます)。

でわでわ。。。