前書き
結論から。
オブジェクト指向とは、現実世界を正しく捉えることです。
オブジェクト指向、全然むずかしくないんですけど、悩んでる人多いですね。この記事を読めば絶対に分かるようになるので、ゆっくり読んでみてください。
想定読者は今まさにオブジェクト指向に苦戦している人たちです。
オブジェクト指向ができた背景とかオブジェクト指向のメリットとかそういうのはググればいくらでも出てくるので、この記事ではオブジェクト指向の本質的なコンセプトにのみ焦点を当てています。
あたまでっかちな説明ばかりで分かりにくかったオブジェクト指向が、5分でサクッと理解できる内容になっています。お楽しみに!
目次
- 理論編
- オブジェクト
- クラス
- プロパティ
- メソッド
- メッセージング
- 実践編
- まとめ
- おまけ
- 継承
- ポリモフィズム
- コンストラクタ
- カプセル化
理論編
オブジェクト
むずかしく考えないでくださいね。オブジェクトとは、物です。物。顔を上げて周りをキョロキョロしてください。物がたくさんありますね。それらがオブジェクトです。いま僕の目の前には電子レンジというオブジェクトがあるので、これを例に解説していきます。
とりあえず、電子レンジについてひたすら説明してみてください。例えば、
- 白い
- 500W
- 10万円で買った
- 食べ物を温めることができる
- 凍ってるものを解凍できる
- 型番はABC-100
などが言えると思います。これでオブジェクト指向で必要な作業の8割くらいは完了です。楽勝ですね。なんとなく分かった気になって、次へ進みましょう。
クラス
これもむずかしく考えないでくださいね。クラスとは、オブジェクトをコードで書いたものです。例えば、
class 電子レンジ {
}
こんな風に書いてあげると、電子レンジというオブジェクトのクラスが出来上がりです。楽勝です。さあさあ、次へ進みましょう。
プロパティ
オブジェクトは、プロパティを持ちます。プロパティは、オブジェクトを説明するデータのことです。さっきの例で言うと「白い」とか「500W」とか「型番はABC-100」とか、これらは全部プロパティです。
これをクラスに書き込んであげましょう。
class 電子レンジ {
色 = 白;
消費電力 = 500W;
型番 = ABC-100;
}
こんな感じです。では、次へ。
メソッド
オブジェクトは、メソッドを持ちます。メソッドは、オブジェクトの動きを説明するものです。さっきの例で言うと「食べ物を温めることができる」とか「凍ってるものを解凍できる」とか、これらは全部メソッドです。
これもクラスに書き込んであげましょう。
class 電子レンジ {
色 = 白;
消費電力 = 500W;
型番 = ABC-100;
温める(食べ物) {
// ここで食べ物を温める
}
解凍する(食べ物) {
// ここで食べ物を解凍する
}
}
こんな感じです。
クラス名が主語、メソッド名が述語、メソッド引数が目的や補語になります。
では次へ。
メッセージング
オブジェクト同士は、メソッドを介して連携することができます。これをメッセージングといいます。オブジェクトのメソッドにメッセージを送るには、「オブジェクト名.メソッド名」と書いてあげます。
例えば人間ってオブジェクトは、電子レンジを使ってご飯を温めますよね。コードにするとこんな感じになります。
class 電子レンジ {
型番 = ABC-100;
温める(食べ物) {
// ここで食べ物をあたためる
}
}
class 人間 {
名前 = せいた社長;
電子レンジで食べ物を温める(食べ物) {
電子レンジ.温める(食べ物)
}
}
main() {
食べ物 = 冷凍パスタ;
人間.電子レンジで食べ物を温める(食べ物)
}
ここが踏ん張りどころです。よく読んでみてください。
実践編
気が向いたら書きます!笑
気が向いたので別記事で書いてみました。
リンク: オブジェクト指向が5000%理解できる記事(実践編)
まとめ
オブジェクト指向を勉強してきた方なら、まあコードを読むのはできたのかなと思います。では、何故オブジェクト指向がむずかしく感じてしまうのか。
それは、現実世界を正しく捉えられていないからです。
オブジェクト指向が出来ない人のプログラムを見ると、電子レンジが勝手に食べ物を温めだしたり、人間が凍っているものを解凍していたりします。そんなこと現実世界ではありえませんよね?
- まず、どんなオブジェクトがあるか整理する
- 各オブジェクトのプロパティを洗い出す
- 各オブジェクトのメソッドを洗い出す
- オブジェクト間のメッセージを洗い出す
これがオブジェクト指向で最初にやるべきことです。いきなりコードを書かないでください。とにかく現実世界に忠実に。
苦手だなって人は、このぬいぐるみってどんなプロパティを持っているんだろうとか、あのスポーツカーってどんなメソッドを持っているんだろうとか、そういうことを考えるようにしてみてください。
おまけ
上記のことができるようになったら、あとは継承とかポリモフィズムとかはおまけみたいなものです。
継承
一応解説しておくと、継承はオブジェクトを特化させるものです。塩おにぎりオブジェクトに、具としてタラコとか鮭とかを追加して、新しくタラコおにぎりとか鮭おにぎりを作ることです。
class 塩おにぎり {
米 = あきたこまち;
具 = 無し;
}
class 鮭おにぎり extends 塩おにぎり {
//書いてないけど米はあきたこまち。継承してるので。
具 = 鮭
}
ポリモフィズム
また、ポリモフィズムは特化したオブジェクトのメソッドを使うものです。
class 機械 {
電源オン() { }
電源オフ() { }
}
class 電子レンジ extends 機械 {
}
class 冷蔵庫 extends 機械 {
}
class テレビ extends 機械 {
}
main() {
電子レンジ.電源オン();
冷蔵庫.電源オン();
テレビ.電源オン();
}
コンストラクタ
コンストラクタは、オブジェクトのプロパティの初期値を設定するものです。
以下の2つの電子レンジを見てください。
class 電子レンジ1 {
色 = 白;
消費電力 = 500W;
型番 = ABC-100;
}
class 電子レンジ2 {
色 = 赤;
消費電力 = 500W;
型番 = ABC-100;
}
ちがいは色が赤か白かだけです。このままだと青とか緑とか微妙に特徴のちがうオブジェクトを作る度にClassを増やさなくてはなりせん。これは長ったらしくて嫌ですよね。
そんな時に便利なのがコンストラクタです。コンストラクタを使うと、Classをオブジェクト化(Classをプログラム内で変数として扱えるように)するタイミングで、プロパティを設定できるようになります。
class 電子レンジ {
色;
消費電力 = 500W;
型番 = ABC-100;
constructor(色情報) {
色 = 色情報;
}
}
main() {
白電子レンジ = new 電子レンジ(白);
赤電子レンジ = new 電子レンジ(赤);
}
Classのメリットは、このように一つのClassという設計図から、たくさんのオブジェクトを生み出せる点にあります。
カプセル化
オブジェクト指向で一番目的が分かりにくいのがカプセル化だと思います。カプセル化というのはオブジェクト化したClassのプロパティを、オブジェクトの外から変更できないようにする考え方です。
ダメな例。
main() {
赤電子レンジ.色 = 白;
赤電子レンジ.消費電力 = 1200W;
}
普通は一度設定した電子レンジの色をそう易々と変えることはできないですよね。製造時(=オブジェクト化時)の一回きりです。
また、もしかしたら消費電力をいきなり変更してしまうと、今温めている物が焦げてしまう可能性もあるかと思います。
そこで、いい例です。
class 電子レンジ {
private 色;
private 消費電力 = 500W;
constructor(色情報) {
色 = 色情報;
}
消費電力変更(消費電力値) {
if 温め中でなければ {
消費電力 = 消費電力値;
}
}
}
まず、プロパティ名の前にprivateと書いてあげることで、Classの外から直接データを変更することができなくなります。
そうすると、色を変更してあげるにはconstructorを使うしかなくなります。つまりデータの変更は、オブジェクト化時の一回きりです。
オブジェクト化以降も変更したいプロパティについては、専用のメソッドを用意してあげることになります。消費電力であれば消費電力変更メソッドです。一度メソッドを経由するメリットは、データを変更する前に条件の確認やデータの整形が行える点にあります。上記の例では、温め中でなければ電力を変更という条件がついています。これにより意図せず食べ物を温め過ぎてしまうリスクを抑えることができます。このように、Class特有のデータの処理を内包してあげるのがカプセル化の目的です。
後書き
ここまで理解できれば、もうオブジェクト指向は完璧。現実世界を正しく捉えることの意味も分かっているはずです。コードを書いたり絵を書いたり、色々と試行錯誤しながら頑張ってみてくださいね!
P.S.
自信がついてきた方は、是非コメント欄も読んでみてください!
P.S. (2019/12/24)
オブジェクト指向とは「現実世界を正しく捉えること」が未だに賛否あるようです。もしドメイン駆動開発(DDD)が「現実世界を正しく捉えること」と言われたらあまり反対意見もないんじゃないかなと思います。オブジェクト指向はDDDの一つの形です。その中で現実世界の観点からではなくプログラミングの観点からオブジェクト指向が拡張されていたりもします。この拡張されたものを正と考えられている方には、なかなかこの記事の内容には賛成しにくいのかなと思います。
実務的なところを考えればチーム内で事前にオブジェクト指向の方向性を合意しておくのが有効だと思いますので、それぞれの流派をしっかり伝えていきたいですね。