ニコニコ大百科モバイル

7/2(月)よりスマホまたはPCでアクセスした場合、各デバイス向けのサイトへ自動で転送致します


オブジェクト指向


ヨミ: オブジェクトシコウ
掲示板をミル!
46カキコ!

オブジェクト指向とは、プログラムひいてはシステムにおける構成要素を
オブジェクトとして捉える概念である。


プログラミングにおけるオブジェクト指向


オブジェクト指向におけるプログラミングとは特定データ構造と振る舞いを持つものを全て物体(オブジェクト)として捉える概念である。

オブジェクト指向では、システム上における、構成要素を分析し、その特徴をまとめてクラスとして定義する。プログラム実行時にクラスの中身としてのデータ群を具体的に決定し、メモリ上にそのデータ群をまとめて配置した塊をオブジェクトと呼ぶ。
クラスにはそのオブジェクトが、どのような内部状態を持つか、どのような操作でどのように内部状態を変化させるべきかを記述する。クラスの構造がプログラム実行前に静的に決まって変更できない言と、実行時であってもクラスの構造の変更を行える言が存在する。

オブジェクトが作用しあって、その内部状態を互いに変化させながら処理が進行するようなプログラムを作ることがオブジェクト指向プログラミングである。オブジェクト指向言と呼ばれる言を使用したとしても、必ずしもオブジェクト指向プログラミングとなるわけではない。

オブジェクト指向プログラミングにおいて、クラスの概念を持つ言プログラミングする場合がほとんどである。しかしクラスというものを排除してオブジェクト指向を実現した言(SelfLENSなど)も存在する。


三大要素



カプセル化


オブジェクト内のデータを隠蔽することにより「振る舞い」のみに意識させるために行う。


継承(インヘリタンス)


オブジェクトの機を引き継ぐことをす。


多態性(ポリモーフィズム)


オブジェクトの詳細な実装が異なっていたたとしても共通した呼び出しで利用することが出来る


もっとわかりやすく言うとどういうこと?


オブジェクト指向はプログラマー初心者にとって、まさに最初のになり、脳味噌パーンと弾けた人も少なくないと思われる。

しかし、それは専門的な用であると決めつけて難しく考えるからいけないのだ。もっとわかりやすく言えば、オブジェクト指向というのはクラスという一つの作業があり、それぞれにメソッドといわれる工程を伴っている、ある的を達成するために必要な作業工程をひとまとめに考えたものと捉えればいい。

例として木版画を挙げてみよう。木版画は名の通り、まず版木に下絵を描き、それに合わせ彫刻で彫り、掘った版木に絵の具を付けて摺ることによって完成する作品である。そして、江戸時代には既に絵師、彫師、摺師による分業制が確立していた。これをラオジェクトwwwという呼び名で名高い(?)Rubyでオブジェクト指向で説明するとこうなる(defは関数定義。また、本来関数変数の名称に漢字やかなは使えないのだが、あくまでわかりやすく説明するため)

class 版画
 def 描く
  #絵師の工程
 end

 def 彫る
  #彫師の工程
 end

   def 摺る
      #摺師の工程
  end
end

このように、オブジェクトというのは一つの単位で現す作業とその作業に必要な工程の集まりなのは説明した通りで(ここでは版画を制作するという作業に対し、描く、彫る、摺るという工程が一つのグループになっている。

そして、絵師が描き、描いた作品を彫師が彫る、彫った作品を摺師が摺る、という工程が行われ、最後の摺る作業が終えて、初めて一つの作品が完成することで、的が達成されるわけである。

作品 = "" #ここに作品が作られていく
版画制作 = 版画.new #今から版画を作ります
作品 = 版画制作.描く
作品 = 版画制作.彫る
作品 = 版画制作.摺る


インスタンス


また、上の版画制作にあたる変数は、インスタンスという。よく、オブジェクト指向を説明したサイトでは雛形などと説明しており、いわば作業マニュアルのようなものである。そして、このインスタンスは基本、与えられた工程以外の作業を命することはない。

また、版画という作業(クラス)に対し、版画制作というインスタンスが与えられることによって、その版画の題材が北斎だろうが広重だろうが、どれも同じように、描く、彫る、摺るという作業が行われるようになる。それは、前述のインスタンスという作業マニュアルが存在するお陰である。

このように、一度作業マニュアルを作ってしまえば、後は同じ作業を繰り返し行える特性インヘリタンス(継承)という。また、このインスタンスに用いる変数名は何を定しても良い。わかりやすく作品名としてもいいし、クラス名と同じにしても良い。


オブジェクト指向の利点とカプセル化


では、このオブジェクト指向、何が便利かというと、似たような作業をグループごとにまとめることができるからである。そして、それによって高い品質を保障できることが大きい。たとえば、この工房では版画以外に彫刻、油なども作っている作業場があるとする。ここで彫刻の作業場で何らかのミスを犯したとしても、版画や油の作業場には何も影がない。これと同じ理屈で、クラス内で起きたバグは、クラス内だけを見直せば済むからである。この作業工程の隠蔽(他の作業場には版画の作業工程は見えない)のことを、カプセル化という。

なお、似たようなものに配列があるが、配列一つの単位におけるグループの集まり配列学校の学年、インデックスクラス番号と思えばいいだろう)であり、作業工程といった動作を伴ったものではない。


変数とスコープ


変数はオブジェクト指向において、少し解釈が面倒である。一般的な変数は、その関数内でしか使えなかったり、そのページ内でしか使えなかったりするものが多い。だが、オブジェクト指向の場合は、大元のクラスにおいて、クラスグループ内ならばどこでも使える変数、そのクラスだけで使える変数、そして、どこでも使える変数などを定義することができる。この変数が及ぶ範囲をスコープという。

例でいえば、この版画の作業で、全部の工程にかかわっているものは版木であり、これを一つの変数としてみる。すると、この”版木”は作業工程の中で絵師鉛筆で描かれたり、彫刻で掘られたり、絵の具を塗られたり、に摺られたりしているわけであり、この”版木”をわざわざ、描く、彫る、塗る工程ごとに”版木です”と定義するのはナンセンスな話である。したがって、この”版木”という変数のスコープは作業全体に定義させた方がいいだろう。

一方、彫刻バレンという具をそれぞれ変数に当てはめてみても、それを使用するのはそれぞれ彫師と摺師だけであるので、これを、版画制作という作業工程全部で定義するのも効率が悪い話である。この場合は、それぞれの彫る、摺るというメソッドだけで定義すれば済む話である。

これをプログラムの話に当てはめてみて、実際のプログラムの中でも変数は、”版木”のようにずっとクラス内で色々代入が行われているほど参照頻度が高いものもあれば、”彫刻”や”バレン”のように、一時的な命や判定なだけに用いられるものもあるわけである。

つまり作業において発生する物や出来事に対して、関係あるものとないものを振り分けることができるのが、変数のスコープの役割である。


セッタとゲッタ


では、変数に軽く触れたところで、駄と下駄…もといセッタゲッタについて解説する。セッタ(setter)とは名の通り、共通で用いる変数を外部から取得する的で作られるメソッドであり、ゲッタ(getter)とは名の通り、クラス内で生成された変数を、元のメインプログラムに返すために作られるメソッドである。

つまり、版画の場合でたとえると、版木、また彫刻バランといった作業具類は元々のメソッドには用意されていないため、外部から仕入れる必要がある。そのために、外部から現在の版画クラスメソッド活用するために、セッタを使い、外部から変数を取り入れるわけである。

対して、ゲッタというのは、そのクラス内におけるメソッドによって完成したもの、あるいは次の工程に必要なものを外部に送り出す役割を持っている。ここで返す必要があるのは摺られた木版画の作品そのものがそれに当たる。上記では作品と表したが、実際にはゲッタで送り返すものは版木そのものではなく、完成品としての木版画そのものがそれに当たる。


コンストラクタ


また、オブジェクト指向にはコンストラクタという仕組みを実装しているものも多い。コンストラクタとは名の通り、構築するものという意味であり、最初のインスタンス実装する際に、同時に変数として送り込み、コンストラクタによって、インスタンス定義用のメソッドで自動的に処理される仕組みであり、いわば料理の下拵えのようなものである。

たとえば、上記の例で、版画制作=版画.Newと記述する際に、インスタンス生成時に変数も設定しておく形となる。そうすれば、次のメソッドが実行される前に、インスタンスを生成したタイミングで、コンストラクタが働き、作業用メソッドを実行する前に、事前処理をしてくれるわけである。

実際の木版画の工程でも、版木が用意されればすぐに絵師が絵を描くものではなく、ある程度、洗浄や研磨といった下準備を行ってから描いていく。これをプログラムに置き換えてみると、

版画制作=版画.New(版木)
作品 = 版画制作.描く

と記述できる。コンストラクタに下準備のプログラム実装しておくことによって、絵師の描くメソッドを実行できるようになる。


継承クラス


次の説明に入る前に、継承クラスの説明をしておこう。

上記の例でいえば、版画における絵師の描く仕事にも構図、描画などの工程がある。また、彫師には彫るなど、摺師には絵の具の調合や摺るなどの作業工程があり、細分化されている。その場合、継承クラスを定義することによって、版画の作業を更に細分化することができる。このうち、版画における絵師の作業を継承クラス化してRubyで表すとこう表現できる。

class 絵師 < 版画
 def 構図
      #構図をとる工程
 end
 
 def 描画
      #描く工程
 end
end

これが継承クラスであり、要は作業工程が更に細かい作業工程へと細分化されているわけである。


ポリモーフィズム(多様性)


さて、カプセル化インヘリタンスはそこまで難しくない。だが、このポリモーフィズムを説明するには、ちょっと木版画だけでは足りないので、この版画作業場では木版画だけでなく、石版画、版画も作るとする。そして、石版画も同様に描く、摺る、彫るという工程があり、担当の絵師は石版画、版画も担当しているとしよう。すると、上述した継承クラスにいる絵師は石版画、版画とも継承クラスの関係にある。このように、同じ名前のメソッド複数のクラスで使い回せるような状態のことをポリモーフィズムという。

下の例では、各クラス内に同じ”描く”というメソッドを定義しているが、それぞれクラス名が異なっているので、同じ描く命でも、実際に実行している工程は異なっているわけである。

class 木版画
    def 描く
  end 
end

class 石版画
     def 描く
   end
end

class 版画
    def 描く
  end
end

class 絵師
 def 描く
 end
end

こういうことである。


抽象クラス


オブジェクト指向の大まかな概念がわかってきたところで、頻出する抽クラスインターフェースの説明をしたいと思う。クラスとは名の通り「具体的なことが記されていない工程」にあたり、上の例だと、絵師クラスがそれに当たる。なぜなら、絵師責任者から「描いて」と言われても、木版画の下絵なのか石版画の下絵なのか、版画の下絵なのか、それとも別の業務なのかわからない(つまり、的にしか工程が命されていない)からである(※なお、Rubyには抽クラスの定義はない)

だが、同時に版木が渡されたら「ああ、木版画ですね」とわかるし、石ならそれぞれ石版画、版画とわかるだろう。このように、抽クラスの場合は、必ず、それの抽的な「描いて」という作業に対し、何を「描く」のか判別する判断材料(ゲッタとセッタを置くことが多く、そこで必要な情報をやりとりする)は上位クラスに用意されている。また、インスタンスも直接継承クラスに対して示しないとエラーとなる。なぜなら、木版画という上位クラスに「描いて」という命を出しても、そこにあるのは作業マニュアル材料だけで、絵師は継承クラスにしか存在しないからである。


インターフェース


対してインターフェースというのは逆の視点となる。それこそ版画の作業場では木版画にしても、石版画にしても版画にしても、絵師に作業を頼むことになるからであり、言い換えれば絵師は木版画や石版画、版画…の継承クラスに位置するわけである。

では、クラスという概念との違いについてであるが、クラスは、作業はそれぞれ複雑な工程があるけど、それによって作られるもの(出される値)は同一種である。それに対しインターフェースは、作業は同じなんだけど、それによって作られるものは多様に富んでいるということである。つまり、上記の例では木版画、石版画、版画などをひっくるめても、結局は描く、彫る、摺るという同じ作業が行われているからである。

なお、継承クラスは複数の親クラス定できないが、インターフェースの場合は複数の親を持つことができる大きな違いがある。


静的メソッド・静的メンバ


さて、今までは同じ作業の中で工程をグループ化するものと定義してきたが、実際はそうでないケースもある。それが静的メソッドあるいは静的メンバであり、ここではクラスに値するものはただの組みでしかなく、クラス名によってカテゴライズしているだけである。たとえば、アメリカ合衆国カジノが合法化されている州とそうでない州があるが、実際その州のカジノが合法であるかは、実際調べてみる必要がある。だが、逆にそれさえわかってしまえば、ほかは調べる必要がない。それを静的メソッドで表現するとこのようになる(Rubyではその概念はなかったので、Pythonで記述する)

class アメリカ合衆国:
    @staticmethod
    def nevada():
        print("カジノは合法です")
    def tennessee():
        print("カジノは違法です")

アメリカ合衆国.nevada() カジノは合法です
アメリカ合衆国.tenessee() #カジノは違法です

別に作業を工程化しているわけではないので、そのメソッドは他のメソッドとは直接関係を持っていないことがわかる(仮に50州のカジノ情報があったとしても、利用者は全部覗かなくても、必要な州の情報さえわかればいいので)。


次へ»
最終更新日: 19/10/18 12:33
タグ検索 パソコン版を見る


[0]TOP
ニコニコ動画モバイル
運営元:ドワンゴ