オブジェクト指向
オブジェクト指向の概要
オブジェクト指向は、「プログラムをクラスという部品に分けて、それらを組み合わせてシステム全体を構築する」という設計・開発手法の一つです。クラス同士を連携させながら、柔軟で拡張性のあるシステムを構築します。
オブジェクト指向でシステムを設計する際にはまず、システムに登場する人や物を想像します。その登場人物(アクター)には、どんな状態を保持する必要があって、どんな挙動をするかを考えるのです。
人の例だと、「名前や年齢」「歩く」などです。
この「名前や年齢」のことを属性と言います。値や状態を保持するもののことです。プログラムでいうと、クラスのフィールドのことです。
「歩く」のような挙動のことを操作と言います。そのクラスのオブジェクトに対する命令のことです。これを、メソッドと言います。
ショッピングサイトをオブジェクト指向で設計してみます。まず登場してくる、人について考えてみましょう。
- 講入者
- 出品者
などが挙げられると思います。仕組み上は明確な区分けはなく、ユーザという1つの枠組みでまとめられているかもしれません。
これだけではないと思いますが、ものについても考えてみましょう。例えば、
- 商品
- 商品名
- 概要
- カテゴリ
- 値段
- 出品者
- レビュー
購入者は商品についてコメントしたり、評価をフィードバックします。
この図はクラスの連携を示していますが、少しずつ部品を具現化しながらシステムを作って連携させていく事を「オブジェクト指向」と言います。実際にプログラムで連携させていくにはクラスを実体化する必要があります。
オブジェクト指向の特徴
- カプセル化
外から見て複雑でない状態を作ること。
- 継承
親クラスの機能を子クラスが引き継ぐこと。
- ポリモーフィズム(多態性)
呼び出し方は共通化するが、実際の振る舞いはクラス毎に変化させること。
クラスとは?
システムで動くモノの設計図のこと。モノとは?オブジェクトのことです。
- 属性
- 操作
を持っています。名前や属性、操作が書かれているオブジェクトの設計図のことです。
フィールドとメソッド
フィールドとは、属性のことです。クラスの直下に宣言された変数を指します。Personクラスというサンプルで言うと、
nameとageのことです。インスタンス変数と呼びます。ローカル変数とはスコープ(有効範囲)が異なります。
メソッドとは、操作のことです。クラス内に書かれた命令文のことです。walkメソッドはPersonクラスにおいてその役割を果たします。
オブジェクトとは?
クラスは設計図なのでそのままではコンピュータ上で動きません。実体化しないと使えません。実体化とは?クラスからオブジェクトを生成することです。これを、インスタンス化と言います。new演算子を使います。Personクラスを実体化してみましょう。
Personクラスの小文字personという名前の変数を宣言すると、スタック領域にpersonの箱が作られます。
で、ヒープ領域にPersonの実体が作られ、変数personから参照されるようになります。
実体化して初めて使えるようになるので、で名前が保存されます。
で年齢が保存されました。
38歳の佐藤さんが歩き始める、ということになるわけです。
name、ageフィールドやwalkメソッドは、クラスを実体化して初めて使えるモノになる、ということです。
インスタンス化について
Personクラスをインスタンス化する際のメモリの状態を見ていきましょう。
Personクラスを使うmainメソッドの中で、
- Personクラスの変数を宣言すると、スタック領域にpersonの箱が作られます。
- すると、ヒープ領域にPersonクラスの実体が作られます。
- それを変数personに代入しているので、変数は実体を参照するようになります。
- nameフィールドは鈴木にageフィールドは50になります。
- introduceメソッドで自己紹介すると、「私は50歳の鈴木です」とメッセージが出力されます。
インスタンスとは?
オブジェクトのことです。インスタンス≒オブジェクトと思っていただいてよろしいのですが、
- オブジェクト
生成したモノの総称
- インスタンス
生成した1つの実体
というようなニュアンスが含まれている、という感じで使い分けています。
staticフィールド
フィールドとメソッドはクラスを実体化しないと使用できませんが、特別なキーワードで使用できるようになります。
というキーワードです。
インスタンス化しなくても使えるようになります。フィールドにはの形式でアクセスします。定数的な意味合いを持つフィールドに使用します。例えば、円周率などです。円周率は、どの円でも共通した値です。オブジェクト固有の情報ではないものに使います。
円クラスがあるとしましょう。
円周率フィールドPIと、x座標、y座標、半径rのフィールドがあります。にはstaticキーワードがついています。これは、3つのインスタンス変数と1つのstatic変数を持つクラスです。
使う側のクラスも見ていきましょう。
mainメソッドの中で、
Circleクラスのインスタンスc1をnewして半径rを5にしています。
もう1つのインスタンスc2は半径10としました。
円周率はオブジェクト固有の情報ではないのでどのような円でも共通です。
メモリ上の一箇所にのみ存在し、実体の中に作られることはありません。
なので、でアクセスすることができます。実体化(new)しなくても使用することができる、ということです。
staticメソッド
という形式で呼び出すことができます。クラスの属性に依存しないメソッドなどに使います。
例えば、mainメソッドなどです。newしなくても実行できていたのはstaticキーワードがついていたからです。
でも、「クラスの属性に依存しない」とはどういうことなのでしょう?具体例を見て解説していきたいと思います。
計算機クラス、Calcです。plusメソッドは、2つのint型の数値を足し算するメソッドです。
Main15クラスはmainメソッドの中でCalcクラスを使って10と5を足し算しています。
Calcクラスのオブジェクトをnewしています。フィールドaに10、bに5を代入してから、plusメソッドを呼び出しています。出力結果は15になりますが、Calcクラスは本当にインスタンス化する意味があったのでしょうか?
足し算に必要な2つの値はクラスに依存しません。変数a、bはフィールドである必要はありません。引数で渡すだけで十分です。plusメソッドは以下のようになります。
引数で足し算する2つの値をもらって計算結果をreturnするstaticメソッドになりました。
main側の処理はこうなります。
newしてフィールドa、bに10と5を代入する処理は不要です。staticメソッドCalc2.plusメソッドの引数に10と5を指定して足し算しています。
オブジェクトの内容に左右されないようなメソッドに使います。
足し算はオブジェクトの内容にかかわらず引数の値によって答えが決まるため、オブジェクトを生成する意味がありません。
メソッドのオーバーロード
メソッドは、1つのクラスの中に同じ名前のものを複数宣言することができるのです。但し、引数の型や数が異なっていなければいけません。
同じ名前のメソッドを1つのクラス内に複数定義することを、メソッドのオーバーロードといいます。
前述の足し算メソッドの例です。
2つのint型の値を足し算していますが、double型の2つの値を足し算したい場合はどうすればよいでしょうか?
小数の足し算メソッドを追加してみました。メソッド名はになっています。でも、足し算という同じ目的であれば、同じ名前で使える方が使う側にとって便利です。
メソッド名は、同じ名前の「plus」が相応しいです。引数aとbのデータ型はdoubleになっています。数は同じですがデータ型が違います。
3つの整数を足し算したい場合はどうなるのでしょうか?
引数はint型ですが、3つあるのでこの宣言が可能です。引数の型や数を変えることで、同じ役割を持つメソッドの名前を同じにすることができます。これをオーバーロードと言います。
「同じ概念を示すものは同じ名前にするのが相応しい」ということです。