こんにちは。
最近勉強会が再開されるようになって嬉しい。
どうもハチマキです。
はじめに
ちゃんと理解を深めていなかったオブジェクト指向。最近やっと1人称で開発ができるようになってきて、開発している中で様々な疑問(Why)が出るようになってきました。
例えば、
- コードの可読性を上げるには、どういう記述にするのが良いのか?
- なぜこういう処理、コード記述をする必要があるのか?
- 記述メソッドにはどういう意味があるのか?適切なのか?
- このコードだと、パフォーマンスはどうなるのか?
などなど、過去を振り返ると「プログラムが呪文に見える → プログラム理解はあまりできてないけど、なんとなくこんな処理が行われている → このプログラムは、〇〇処理を行なっている」と段階を踏んで理解が進んできました。
現在Railsをメインに開発を行なっており、疑問の中の一つにオブジェクト指向って結局何なんだ?どう活用していけば、より良いプログラムになるんだろうか?こんな疑問をふと持つようになりました。
今回はこの疑問に応えるべく、オブジェクト指向についてなるべく理解(自分の口で喋れるようになる)を上げるため、言葉を噛み砕いて書いてみました。
おそらく15分程度で読める内容になっているかと思います!(内容に誤りがありましたら申し訳ございません)
対象
*コードを踏まえた説明はしておりません。
目次
オブジェクト指向とは?オブジェクト指向言語とは?
まずは、Wikipedia先生に伺いましょう。
オブジェクト指向とは、ソフトウェア開発とコンピュータプログラミングのために用いられる考え方である。
元々は特定のプログラミングパラダイムを説明するために考案された言葉だった。明確な用語としては1970年代に誕生し、1980年代前半に知名度を得て、考案者の手を離れた自由で曖昧な定義のまま発展を続けた後に、1990年代に入るとソフトウェア工学の様々な分野にも応用されるようになった。ソフトウェア開発における一つの標語のような扱い方もされている。
ふむふむ。
つまりプログラミングの考え方や記述方法の枠組み(プログラミングパラダイム)であるということですね。
次にオブジェクト指向言語とは何か?について、またWikipedia先生に伺います。
オブジェクト指向プログラミングとは、互いに密接な関連性を持つデータ(変数またはプロパティ)とコード(関数またはメソッド)をひとつにまとめてオブジェクトとし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。
何言ってんだ?関連データと処理をまとめた集まり?オブジェクト?
早速何がなんだか理解できません。
オブジェクト指向言語について様々調べていると、
- オブジェクト=モノ
- 互いに関連するデータの集合とそれらに対する手続き群をひとまとめにしたオブジェクト
などの説明が多く見受けられました。正直なんとなくわかったようなわからんようなです。
もう少し理解を深めるため、少し歴史から順を追っていきました。
*今回様々調べて得た解は、オブジェクト指向言語とは、関連する情報(データ)の集まりと挙動をひとまとめにした「モノの集まり」だということです。
プログラミング言語の歴史
プログラミング言語の歴史は、1930年ごろに遡ります。(意外と最近にびっくりしました)
プログラミングの歴史は1900年代〜と、思っていた以上に歴史が浅い。にも関わらず進化のスピードは早いことを調べてる中で感じました。
オブジェクト指向自体の誕生は、1970年前後に生まれ、最初に提唱したのは、計算機科学者アラン・ケイ氏と言われております。1972年から開発公開を始めた「Smalltalk」の言語設計を説明する中でオブジェクト指向は発信され、1981年頃から知名度を得た概念です。
そして知名度を得た背景には、コンピュータの急激な進歩によって、より複雑なソフトウェアが求められ始めたこと(時代)が大きく関連しています。
それが、次に説明するソフトウェア危機というものです。簡単にどんなものなのか書いていきます。
ソフトウェア危機とは?
そもそもソフトウェア危機とは、ソフトウェア工学がまだ十分に確立していなかった頃、よく使われた言葉です。
▼詳しくはこちらから
ソフトウェア危機 - Wikipedia
端的にいうと、ソフトウェアの発展が、利用者(市場)の求める需要を満たすだけの生産量・品質・費用・時間の面で追いつかず、供給できないという問題や課題を指します。
それら問題により、具体的に開発プロジェクトでは下記のような実態が顕著に現れていました。
▼Wikipedia先生の引用
・予算を超過してしまったプロジェクト
・予定期間を超過してしまったプロジェクト
・品質の低いソフトウェア
・要求仕様を満たさないソフトウェア
・管理不能状態のプロジェクトと、保守困難となったコード
オブジェクト指向の成り立ち
ソフトウェア危機が叫ばれた背景には、プログラムの複雑化とバグ問題が密に関わっています。
これはつまりコンピュータの性能が向上したことで、従来より大規模なソフトウェアが書かれることになり、プログラムの複雑化やプログラム保守が難航(追加や修正がより困難)する問題へと発展しました。(プログラムは複雑化する一方なのに、管理手法もなければ、データ型は基本的な数値でしかなかったわけです)
これら問題を解決するために目指したことは、「開発効率の向上」や「メンテナンス性の向上」です。
上記を目指す上で、様々な手法や方法論が開発される中考えられたのが、プログラムの独立性、再利用性、拡張性の3つを追求するということです。
そして、その3つの性質を兼ね備えた概念こそ、オブジェクト指向なのです。(継承・カプセル化・ポリモーフィズム)
やっとつながってきました。
オブジェクト指向の本質(2021-05-14追記)
オブジェクト指向の本質は、いかにコード間の依存関係を減らし(疎結合),メンテナンスしやすいプログラムを書くかです。
そのためには、コードをある程度の固まりとしてグループ化を行い、コードの依存関係を排除する。つまり「粗結合」を意識しながらコード間の依存関係を最小に保つように心がける必要があります。
*なぜメンテナンスしやすいプログラムを書く必要があるのか?(密結合ではダメなの?)
結論は、生産効率を上げるため。だと私は認識しております。
機能ごとの独立性が高い事で、あるコードを変更しても(別コードへの)副作用を与えることがなくなるからです。
密結合(コード間の依存関係が高い)の場合、手もつけられないぐらい複雑に絡み合ったコードの固まりができてしまう。つまり数行のコードを追加・変更するだけでさまざまな副作用を考慮しなければいけなくなり,生産効率が極端に下がりはじめます。(あるコードを変更すると、他のコードで別の問題が発生するなど)
以下(継承は、疎結合と矛盾する面あり)は、これらを実現させるための手段と私は認識しています。
第4回 オブジェクト指向の本質:Software is Beautiful|gihyo.jp … 技術評論社
オブジェクト指向の価値
では次に、オブジェクト指向の最大の価値は何かについてです。
早速結論ですが、それは「抽象化による、わかりやすさと利便性」にあります。
んーよくわからんですね。。なので、いきなりですが一例あげたいと思います。
我々の自然言語の世界では、例えばボール(Ball)を見ると、これはボールだ!と認識できます。
そして同様にリンゴ(Apple)を見れば、これはリンゴだ!と認識できるはずです。
プログラムの世界では、そうはいきません。ボールを見てもボールとは認識出来ませんし、リンゴを見ても同様に認識が出来ません。
では、どうするのか?
ボールは、転がる・跳る・丸い・皮膜や外殻に包まれている、リンゴは、赤い・丸い・甘い・食べるのように、関連する情報(データ)と挙動をひとまとめにしたモノ(オブジェクト)に名前をつけることで、ボールはボールになり、リンゴはリンゴになり、そして認識できるようになります。
我々の自然言語の世界では、ボールやリンゴは、すでに情報が抽象化されたモノの名前を使って、それらを認識し活用しています。
日常会話の中で、転がる・跳る・丸い・皮膜や外殻に包まれているのを買いに行くんだよね!というより、ボールを買いに行くと言った方が自然でわかりやすいですよね?
つまりこれが抽象化であり、このプログラミングパラダイム(概念)がオブジェクト指向です。
ただ抽象化だけでは、価値を実現させることができません。
次に説明する継承、カプセル化、ポリモーフィズム(多態性)の3大要素をうまく活用する(組み合わせる)ことが重要です。
▼組み合わせることで、下記のようなメリットをもたらすことができます。
- システムの柔軟性が増す
- カスタマイズがしやすくなる
- スムーズな作業につながる
- 開発者同士での認識の共有がしやすくなる
- 開発作業の効率化を図れる
- 再利用がしやすい
*デメリット
オブジェクト指向の3大要素
1つ目:継承
▼Wikipedia先生から引用
継承(けいしょう、英: inheritance、インヘリタンス)とはオブジェクト指向を構成する概念の一つである。あるオブジェクトが他のオブジェクトの特性を引き継ぐ場合、両者の間に「継承関係」があると言われる。
主にクラスベースのオブジェクト指向言語で、既存クラスの機能、構造を共有する新たなクラス(派生クラス、派生型)を定義すること(subclassing、サブクラス化)ができる。またそのような派生クラスは「親クラス(スーパークラス)を継承した」という。具体的には変数定義(フィールド)や操作(メソッド)などが引き継がれる。またJavaやC#などのインタフェース実装のように、機能セットの仕様(プロトコル)のみを引き継ぐ場合もある。
一般的に、BがAを継承する場合、"B is a A."(BはAの一種である)という意味的な関係(Is-a関係)が成り立つ。従って、同じふるまいを持つからと言って、意味的に無関係なクラス間に継承関係を持たせるのは適切でない場合が多い。
継承は、再利用の仕組みです。
継承を利用することで、親クラスを継承した新しいクラス(派生クラス)は、メッセージ・メソッド・属性といった親クラスの構造を受け継ぐことができます。つまり、派生クラスでは、親クラスの構造を再利用でき、新たに機能を実装することが可能になるということです。
もう少しわかりやすく、ボールを例に説明していきます。
例えば、サッカーボールを作る時、一からボールの情報を定義する。テニスボールを作る時もまた同様、一からボールの情報を定義する。これ結構めんどくさくないですか?
できればすでにあるボールという概念(情報)にサッカーボール特有の情報を加えるだけで、サッカーボールにできた方が良くないですか?
プログラムの世界でも同様です。
サッカーボールとテニスボールの抽象度をあげると、どちらもボールです。定義したボールの情報を継承すると、ボールに関連する情報や挙動を再利用することが出来ます。
つまりサッカーボールを作りたければ、継承したボールの情報に黒と白の色の情報、大きさの情報などを加えるだけで、サッカーボールにすることができるのです。
このボールに関連する情報や挙動を使うことこそ、再利用の仕組みであり、継承なのです。
▼メリット
- コードの追加・修正といったメンテナンスが容易になる
- より抽象的な共通する機能を親クラスにまとめることができる
- コードが読みやすくなる(可読性が上がる)
*継承を利用する上で重要なことは、クラス同士の関係が派生クラス is a 親クラス(派生クラスは親クラスの一種である)という意味的な関係(Is-a関係)を築く必要があります。
*今回の例だと、サッカーボール is a ボール(サッカーボールはボールの一種である)という関係です。
逆転の発想でオブジェクト指向の「継承」を使いこなす | IT × マーケティング コラム
【オブジェクト指向】クラスの継承とは?【プログラミング】 | 初心者向け完全無料プログラミング入門
【第3回】継承 (1/4):CodeZine(コードジン)
2つ目:カプセル化
▼Wikipedia先生から引用
カプセル化(カプセルか、英: encapsulation)とは、データ(属性)とメソッド(手続き)を一つのオブジェクトにまとめ、その内容を隠蔽することを言う。
カプセル化は、一つのオブジェクトとしての独立性を高める仕組みです。
カプセル化を利用することで、データのアクセスを制限(不整合を引き起こすような操作をできなくする)し、データを保護することで、オブジェクトの安全性を高めることができます。
データアクセスの可否はアクセス指定子(private/public)と呼ばれるものによって決められ、クラスやオブジェクト外からのデータアクセスに制限(拒否)をかけることができます。
つまり!先ほどの例を使うと、サッカーボールの情報を勝手に、色を白と緑に、大きさを拳くらいに変えられたら困りませんか?
これサッカーボールなのに、なんかテニスボールみたいになってるやん!ってなりますよね。。(情報が壊れる)
これが一つのオブジェクト(サッカーボール)としての独立性を高める仕組みであり、カプセル化なのです。
▼メリット
- 仮に異常なデータ変更が来た場合は、適切な値に戻したり、変更を拒否することができる
- 予期せぬバグを防止できる
- 情報を直接操作することをできなくし、情報が壊れてしまうことを防止できる
カプセル化とはなにか?超わかりやすく解説します! | じゃぱざむ
オブジェクト志向のカプセル化を、総合医療病院で例えると「窓口」という説を語ってみる。 | IT × マーケティング コラム
3つ目:ポリモーフィズム(多態性)
▼Wikipedia先生から引用
ポリモーフィズム(英: Polymorphism)とは、プログラミング言語の型システムの性質を表すもので、プログラミング言語の各要素(定数、変数、式、オブジェクト、関数、メソッドなど)についてそれらが複数の型に属することを許すという性質を指す。ポリモルフィズム、多態性、多相性、多様性とも呼ばれる。対義語はモノモーフィズム (Monomorphism)、単態性、単相性で、プログラミング言語の各要素が唯一つの型に属するという性質を指す。
ポリモーフィズムは、拡張性の仕組みです。
異なる型のオブジェクトを同一視し、そのオブジェクトの型によって動作を切り替えることが可能になります。
もう少し細かくいうと、物事を抽象概念として捉え、一つの命令に対し、各々が持った別の動き(振る舞い)を可能にします。
例でいうと、ボール・サッカーボール・テニスボールってどれも跳ね方が異なります。この「跳ねる」という挙動を、サッカーボールとテニスボールに合わせて、別々の跳ね方に書き換える(オーバーライド)と、その跳ね方に変えてくれます。(呼び出し先に応じて、適切なメソッドが実行されることで、良しなに振る舞いが変化する)
つまり跳ねるという挙動(同じメソッド名)でも、ボール・サッカーボール・テニスボール(オブジェクト)の変化に応じて、結果が変わることはポリモーフィズムの拡張性の仕組みなのです。
▼メリット
- 何度も同じコードを書く必要がなくなるため、コードがきれいになる
- プログラムの読みやすさが向上する
- プログラムの再利用のしやすさが増す
【オブジェクト指向とは何ぞや】ポリモーフィズムとダックタイピングを理解しよう | shin>>media
ポリモーフィズム(多相性)とは - IT用語辞典 e-Words
プログラマー1年生がポリモーフィズムについて学んだのでRPGで説明する。 - Qiita
まとめ
以上で、一通りオブジェクト指向の説明が終わりました。いかがだったでしょうか。
様々調べて得た私の解は、オブジェクト指向言語とは、関連する情報(データ)の集まりと挙動をひとまとめにした「モノの集まり」だということです。
そしてオブジェクト指向言語において特に重要なことは、継承・カプセル化・ポリモーフィズムをうまく組み合わせるということです。
今回を通して、オブジェクト指向の理解は、だいぶ進んだように思います。
ただあくまで、オブジェクトを使ったプログラム全体を構築する手法であるということ、そして概念だけを理解したからといって、実際のプログラムに実装できるかはまた別問題だというです。
なので、次は実践に活かせるようオブジェクト指向設計実践ガイドを読んでみようと思います。