7/2(月)よりスマホまたはPCでアクセスした場合、各デバイス向けのサイトへ自動で転送致します
オブジェクト指向とは、プログラムひいてはシステムにおける構成要素を
オブジェクトとして捉える概念である。
オブジェクト指向におけるプログラミングとは特定のデータ構造と振る舞いを持つものを全て物体(オブジェクト)として捉える概念である。
オブジェクト指向では、システム上における、構成要素を分析し、その特徴をまとめてクラスとして定義する。プログラム実行時にクラスの中身としてのデータ群を具体的に決定し、メモリ上にそのデータ群をまとめて配置した塊をオブジェクトと呼ぶ。
クラスにはそのオブジェクトが、どのような内部状態を持つか、どのような操作でどのように内部状態を変化させるべきかを記述する。クラスの構造がプログラム実行前に静的に決まって変更できない言語と、実行時であってもクラスの構造の変更を行える言語が存在する。
各オブジェクトが作用しあって、その内部状態を互いに変化させながら処理が進行するようなプログラムを作ることがオブジェクト指向プログラミングである。オブジェクト指向言語と呼ばれる言語を使用したとしても、必ずしもオブジェクト指向プログラミングとなるわけではない。
オブジェクト指向プログラミングにおいて、クラスの概念を持つ言語でプログラミングする場合がほとんどである。しかしクラスというものを排除してオブジェクト指向を実現した言語(SelfやLENSなど)も存在する。
オブジェクト内のデータを隠蔽することにより「振る舞い」のみに意識させるために行う。
オブジェクトの詳細な実装が異なっていたたとしても共通した呼び出しで利用することが出来る
▲オブジェクト指向はプログラマー初心者にとって、まさに最初の壁になり、脳味噌がパーンと弾けた人も少なくないと思われる。
しかし、それは専門的な用語であると決めつけて難しく考えるからいけないのだ。もっとわかりやすく言えば、オブジェクト指向というのはクラスという一つの作業があり、それぞれにメソッドといわれる工程を伴っている、ある目的を達成するために必要な作業工程をひとまとめに考えたものと捉えればいい。
例として木版画を挙げてみよう。木版画は名の通り、まず版木に下絵を描き、それに合わせ彫刻刀で彫り、掘った版木に絵の具を付けて摺ることによって完成する作品である。そして、江戸時代には既に絵師、彫師、摺師による分業制が確立していた。これをテラオブジェクト指向wwwという呼び名で名高い(?)Rubyでオブジェクト指向で説明するとこうなる(defは関数定義。また、本来関数や変数の名称に漢字やかなは使えないのだが、あくまでわかりやすく説明するため)
このように、オブジェクトというのは一つの単位で現す作業とその作業に必要な工程の集まりなのは説明した通りで(ここでは版画を制作するという作業に対し、描く、彫る、摺るという工程が一つのグループになっている。
そして、絵師が描き、描いた作品を彫師が彫る、彫った作品を摺師が摺る、という工程が行われ、最後の摺る作業が終えて、初めて一つの作品が完成することで、目的が達成されるわけである。
作品 = "" #ここに作品が作られていく
版画制作 = 版画.new #今から版画を作ります
版画制作.描く
版画制作.彫る
作品 = 版画制作.摺る
また、上の版画制作にあたる変数は、インスタンスという。よく、オブジェクト指向を説明したサイトでは雛形などと説明している。だが、これ自体は実体を伴っているものではなく、どちらかというとクラスという作業における作業マニュアルのようなものである。このインスタンスは基本、与えられた工程以外の作業を命令することはない。
また、版画という作業(クラス)に対し、版画制作という作業マニュアル(インスタンス)が与えられることによって、その版画の題材が北斎だろうが広重だろうが、どれも同じように、描く、彫る、摺るという作業が行われるようになる。
このように、一度インスタンスを作ってしまえば、後は同じ作業を繰り返し行える特性をインヘリタンス(継承)という。また、このインスタンスに用いる変数名は何を指定しても良い。わかりやすく作品名としてもいいし、クラス名と同じにしても良い。
では、このオブジェクト指向、何が便利かというと、似たような作業をグループごとにまとめることができるからである。そして、それによって高い品質を保障できることが大きい。たとえば、この工房では版画以外に彫刻、油彩なども作っている作業場があるとする。ここで彫刻の作業場で何らかのミスを犯したとしても、版画や油彩の作業場には何も影響がない。これと同じ理屈で、クラス内で起きたバグは、クラス内だけを見直せば済むからである。この作業工程の隠蔽(他の作業場には版画の作業工程は見えない)のことを、カプセル化という。
なお、似たようなものに配列があるが、配列は一つの単位におけるグループの集まり(配列を学校の学年、インデックスをクラス番号と思えばいいだろう)であり、作業工程といった動作を伴ったものではない。
変数はオブジェクト指向において、少し解釈が面倒である。一般的な変数は、その関数内でしか使えなかったり、そのページ内でしか使えなかったりするものが多い。だが、オブジェクト指向の場合は、大元のクラスにおいて、クラスのグループ内ならばどこでも使える変数、そのクラスだけで使える変数、そして、どこでも使える変数などを定義することができる。この変数が及ぶ範囲をスコープという。
例でいえば、この版画の作業で、全部の工程にかかわっているものは版木であり、これを一つの変数としてみる。すると、この”版木”は作業工程の中で絵師に鉛筆で描かれたり、彫刻刀で掘られたり、絵の具を塗られたり、紙に摺られたりしているわけであり、この”版木”をわざわざ、描く、彫る、塗る工程ごとに”版木です”と定義するのはナンセンスな話である。したがって、この”版木”という変数のスコープは作業全体に定義させた方がいいだろう。
一方、彫刻刀、バレンという道具をそれぞれ変数に当てはめてみても、それを使用するのはそれぞれ彫師と摺師だけであるので、これを、版画制作という作業工程全部で定義するのも効率が悪い話である。この場合は、それぞれの彫る、摺るというメソッドだけで定義すれば済む話である。
これをプログラムの話に当てはめてみて、実際のプログラムの中でも変数は、”版木”のようにずっとクラス内で色々代入が行われているほど参照頻度が高いものもあれば、”彫刻刀”や”バレン”のように、一時的な命令や判定なだけに用いられるものもあるわけである。
つまり、作業において発生する物や出来事に対して、関係あるものとないものを振り分けることができるのが、変数のスコープの役割である。
では、変数に軽く触れたところで、雪駄と下駄…もといセッタとゲッタについて解説する。セッタ(setter)とは名の通り、共通で用いる変数を外部から取得する目的で作られるメソッドであり、ゲッタ(getter)とは名の通り、クラス内で生成された変数を、元のメインプログラムに返すために作られるメソッドである。
つまり、版画の場合でたとえると、版木、また彫刻刀やバランといった作業道具類は元々のメソッドには用意されていないため、外部から仕入れる必要がある。そのために、外部から現在の版画クラスのメソッドで活用するために、セッタを使い、外部から変数を取り入れるわけである。
対して、ゲッタというのは、そのクラス内におけるメソッドによって完成したもの、あるいは次の工程に必要なものを外部に送り出す役割を持っている。ここで返す必要があるのは摺られた木版画の作品そのものがそれに当たる。上記では作品と表したが、実際にはゲッタで送り返すものは版木そのものではなく、完成品としての木版画そのものがそれに当たる。
また、オブジェクト指向にはコンストラクタという仕組みを実装しているものも多い。コンストラクタとは名の通り、構築するものという意味であり、最初のインスタンスを実装する際に、同時に変数として送り込み、コンストラクタによって、インスタンス定義用のメソッドで自動的に処理される仕組みであり、いわば料理の下拵えのようなものである。
たとえば、上記の例で、版画制作=版画.Newと記述する際に、インスタンス生成時に変数も設定しておく形となる。そうすれば、次のメソッドが実行される前に、インスタンスを生成したタイミングで、コンストラクタが働き、作業用のメソッドを実行する前に、事前処理をしてくれるわけである。
実際の木版画の工程でも、版木が用意されればすぐに絵師が絵を描くものではなく、ある程度、洗浄や研磨といった下準備を行ってから描いていく。これをプログラムに置き換えてみると、
と記述できる。コンストラクタに下準備のプログラムを実装しておくことによって、絵師の描くというメソッドを実行できるようになる。
上記の例でいえば、版画における絵師の描く仕事にも構図、描画などの工程がある。また、彫師には彫るなど、摺師には絵の具の調合や摺るなどの作業工程があり、細分化されている。その場合、継承クラスを定義することによって、版画の作業を更に細分化することができる。このうち、版画における絵師の作業を継承クラス化してRubyで表すとこう表現できる。
これが継承クラスであり、要は作業工程が更に細かい作業工程へと細分化されているわけである。
さて、カプセル化とインヘリタンスはそこまで難しくない。だが、このポリモーフィズムを説明するには、ちょっと木版画だけでは足りないので、この版画作業場では木版画だけでなく、石版画、銅版画も作るとする。そして、石版画も同様に描く、摺る、彫るという工程があり、担当の絵師は石版画、銅版画も担当しているとしよう。すると、上述した継承クラスにいる絵師は石版画、銅版画とも継承クラスの関係にある。このように、同じ名前のメソッドを複数のクラスで使い回せるような状態のことをポリモーフィズムという。
下の例では、各クラス内に同じ”描く”というメソッドを定義しているが、それぞれクラス名が異なっているので、同じ描く命令でも、実際に実行している工程は異なっているわけである。
class 木版画
def 描く
end
end
class 石版画
def 描く
end
end
class 銅版画
def 描く
end
end
こういうことである。
オブジェクト指向の大まかな概念がわかってきたところで、頻出する抽象クラス、インターフェースの説明をしたいと思う。抽象クラスとは名の通り「具体的なことが記されていない工程」にあたり、上の例だと、絵師クラスがそれに当たる。なぜなら、絵師は責任者から「描いて」と言われても、木版画の下絵なのか石版画の下絵なのか、銅版画の下絵なのか、それとも別の業務なのかわからない(つまり、抽象的にしか工程が命令されていない)からである(※なお、Rubyには抽象クラスの定義はない)
だが、同時に版木が渡されたら「ああ、木版画ですね」とわかるし、石板、銅板ならそれぞれ石版画、銅版画とわかるだろう。このように、抽象クラスの場合は、必ず、それの抽象的な「描いて」という作業に対し、何を「描く」のか判別する判断材料(ゲッタとセッタを置くことが多く、そこで必要な情報をやりとりする)は上位クラスに用意されている。また、インスタンスも直接継承クラスに対して指示しないとエラーとなる。なぜなら、木版画という上位クラスに「描いて」という命令を出しても、そこにあるのは作業マニュアルと材料だけで、絵師は継承クラスにしか存在しないからである。
対してインターフェースというのは逆の視点となる。それこそ版画の作業場では木版画にしても、石版画にしても銅版画にしても、絵師に作業を頼むことになるからであり、言い換えれば絵師は木版画や石版画、銅版画…の継承クラスに位置するわけである。
では、クラスという概念との違いについてであるが、クラスは、作業はそれぞれ複雑な工程があるが、それによって作られるもの(出力される値)は同一種である。それに対しインターフェースは、作業は同じだが、それによって作られるものは多様に富んでいるということである。つまり、上記の例では木版画、石版画、銅版画などをひっくるめても、結局は描く、彫る、摺るという同じ作業が行われているからである。
なお、継承クラスは複数の親クラスを指定できないが、インターフェースの場合は複数の親を持つことができる大きな違いがある。
▲さて、今までは同じ作業の中で工程をグループ化するものと定義してきたが、実際はそうでないケースもある。それが静的メソッドあるいは静的メンバであり、ここではクラスに値するものはただの枠組みでしかなく、クラス名によってカテゴライズしているだけである。たとえば、アメリカ合衆国はカジノが合法化されている州とそうでない州があるが、実際その州のカジノが合法であるかは、実際調べてみる必要がある。だが、逆にそれさえわかってしまえば、ほかは調べる必要がない。それを静的メソッドで表現するとこのようになる(Rubyではその概念はなかったので、Pythonで記述する)
class アメリカ合衆国:
@staticmethod
def nevada():
print("カジノは合法です")
def tennessee():
print("カジノは違法です")
別に作業を工程化しているわけではないので、そのメソッドは他のメソッドとは直接関係を持っていないことがわかる(仮に50州のカジノ情報があったとしても、利用者は全部覗かなくても、必要な州の情報さえわかればいいので)。