はてなキーワード: カプセル化とは
手続き型言語をやっていると、データを組み合わせて取り扱う必要が出てくる。
例えば、顧客のデータを扱う必要があるとき、顧客の「名前、住所、所属、電話番号、取引内容...」などをまとめて取扱いたい。
そこで、構造体という発想が出てくる。
構造体を扱っていると、新しく顧客データを作るとき、毎回毎回、作った後に同じ動作をしないといけないことに気づく。
そしたら、それをいっぺんにやってしまうために関数を作ることになるだろう。
init_customer(struct Customer*, char* name, char* addr, char* tel)
また、逆に顧客データが不要になったとき、メモリ解放などをさせるために、
delete_customer(struct Customer*)
も作ることになるだろう。
さらに、取引を行うたびに、取引データを追加しないといけない。そのために、このような関数を作るだろう。
add_deal_customer(struct Customer*, char* deal_name, char* deal_ammount)
そして、複数人でプログラムを作っていると
「おいおい!せっかく取引データ追加用のadd_deal_customer作ったのに、なんで自分で勝手に追加してるんだよ!てか、その方法だとメモリ解放どうすんの?ちゃんと作ったの使ってくれたら、delete_customer()でできるようになってるのに」
って状況が生じうる。それを防止するために、コメントに
「/* 取引データの追加は必ずadd_deal_customerを使うこと! */」
と書くことになるだろう。
てか、わざわざコメント書いたのにこいつ読んでねーし。あーあ、めんどくさいめんどくさい。
そこで、だ。言語を少し別のものにかえて、構造体に関数を持たせられるようにしよう。
そして、構造体ができたときに、自動でinitって関数を、削除されるときに、自動でdelって関数を呼ぶとしよう。
そして、add_deal_customerも構造体の中に入れてしまおう。名前は長くて面倒なので、
Customer.add_deal(char* deal_name, char* deal_ammount)
のようにしてしまおう。
さらに、add_dealを使わずに直接、取引データを追加しやがるならず者対策も付け加えてしまおう。
privateにした変数は、構造体が持ってる関数からしか、いじくれないようにしてやろう。
今まではコメント読まない馬鹿の世話に苦労していたのだが、これからはコンパイラがそういうやつにエラーを出してくれる。
次は継承のお話。話は変わって、今度はGUIパーツで説明する。
ボタンってあるよね。あれを作りたい。
普通に文字が書いてあって押したら何かが起こるボタン、アイコンが描いてあって押したら何かが起こるボタン、
この2つを作りたい。
まず、文字のボタンを作ろう。
関数を持てる構造体を作り、「表示する文字(変数)、クリックしたときの動作を定義する関数へのポインタ(変数)、描画命令が出た時に描画する関数(関数)、クリック命令を受け取り、構造体にセットされた関数へのポインタを呼び出す関数(関数)」
がいるかな。
次に、アイコンのボタン。「表示するアイコン(変数)、クリックしたときの動作を定義する関数へのポインタ(変数)、描画命令が出た時に描画する関数(関数)、クリック命令を受け取り、構造体にセットされた関数へのポインタを呼び出す関数(関数)」
あ、さっき作ったのとほぼ同じじゃーん!文字ボタンの構造体をコピペしちゃえ!
あとは文字の変数を、アイコンに変えて、描画命令を、文字描画からアイコン描画に変えればできるじゃん!
ところが、文字ボタンのクリック命令を受け取る関数にバグが見つかった!よし、デバッグできた!
けど、アイコンのボタンにコピペしてたんだった!またコピペしなおしじゃん。あーめんどくさ。
もしそれ以外に、チェックボックスのボタンとか、もっと別のボタンとか、いろいろコピペで作ってたらもっとめんどくさ。
そこで、こんなことができたらいいんじゃないか?
文字ボタンにも、アイコンのボタンにも共通する、関数をもった構造体を作っておく。
ボタンの構造体「クリックしたときの動作を定義する関数へのポインタ(変数)、クリック命令を受け取り、構造体にセットされた関数へのポインタを呼び出す関数(関数)」
そして、文字ボタンは、ボタンの構造体に「表示する文字(変数)、描画命令が出た時に描画する関数(関数)」を、
アイコンのボタンは、ボタンの構造体に「表示するアイコン(変数)、描画命令が出た時に描画する関数(関数)」を追加すればいいんだ。
これを、継承と呼ぶ。
さらに、文字ボタンもアイコンのボタンも、同じ「ボタンの構造体」を持っているから、どっちも同じ「ボタン」として扱うことができる。
後で画面内のボタンを全部解放する必要があるときとか、実はこれ、すごく便利。
別の構造体で扱っていたら、文字ボタン用の配列とアイコンボタン用の配列を用意し、それぞれに作ったボタンをいれ、解放するときはそれぞれの配列の中身を解放しないといけない。めんどくさ。
けど、どっちもボタンを継承しているから、ボタンの配列を用意して、文字ボタンもアイコンボタンも全部同じ配列に入れて、1つの配列の中身を解放したらいい。楽ちん。
はい、そうすると、関数を持った構造体はもはや、もとの構造体とは違う感じになりました。
これをクラスと呼びましょう。クラスから作られたデータは、オブジェクトと呼びましょう。
なんか、オブジェクトがほかのオブジェクトから独立してカプセル化されてるみたいですね。
そして、オブジェクトが持ってる関数。メソッドとでも呼びましょうか。これ、まるでオブジェクトが自分のやりたいことを知っているかのようです。
手続きを構造体や関数に細かく分離していくにつれて、構造体と関数の組み合わせってのが出てきて、まとまりが見えてくるのです。
そいつらをまとめてしまって、一つの部品として扱って、外からはあんまり部品の中身を見えないようにしましょう。
部品の中身を直接いじらせるんじゃなくて、部品をいじらせるための関数を用意して、それを経由してやってもらいましょう。
それが、カプセル化とかいうやつです。
開発効率性を重要視するか、モジュールとしての錬度を重要視するのか、それが問題だ。ここで一つの提案をする。
開発途上において、どの変数を private にすべきで、どの変数に getter が必要で、どの変数に setter が必要で、
どの関数を private にすべきなのかを悩んでいては、本当に重要なところ、つまりアルゴリズムに時間をかけられない。
まずは、アジャイルプロトタイピングをするのだ。その時にカプセル化に頭を悩ますのは良い方法ではない。
コードでやることが決まった後、それをモジュール、ライブラリとして完成度をあげるリファクタリングの段階で、
カプセル化、クラス、関数名、関数の再利用性について頭を悩ますのが効率が良い。
ただし、イケプログラマに限る。
ダメプログラマにやらせると、アジャイルプロトタイピングの段階で、全ての処理が1つの関数に書いてあるなどということになりうる。
類似の処理がほぼコピペということになりうる。リファクタリングの作業が、もはやリファクタリングではなく、リストラクチューリングになりうる。
そりゃ「影響」はしてるだろうがな。別にキリスト教の神である必然性などない。/いや、親鸞の書いたものは当然古語で書かれてるでしょ?
いや、自明とか間違いなくとか言われてもなあ。具体的に挙げてくれる? 君の議論の最大の弱点って多分具体性がないことだから。
グレコ・ローマン文化の話じゃなかったのかよ。近代以降ならそりゃ当然だろ。
いや君がニュートンを引き合いに出したんでしょうに。民主主義に関してはギリシャにまで遡って意義深い書籍を見つけることは出来るだろうなあ。
ほら、君は「??だとすれば」という仮定が読めないんだよね。
で、いつまで撤回した仮定を引きずるわけ?w
何かひとつ共通言語がないとITなんてやってられん、というのは厳然たる事実だろ。
一方で、文化資本による格差なんぞないほうがいいに決まってる。
東大卒は毎年数千人だ。それで、MIT卒は何人いるか知ってる?ハーバードは?プリンストンは?スタンフォードは?オックスフォードは?ケンブリッジは?
数千人か。なおさらたいしたことないな。で、MIT卒全員をエリートと呼んだ覚えはないが?(他の大学もね)。
まあそうね。勝手にどこかで学んできそうな気はする。
教育ってのは、特に公教育ってのは、底上げのためにやるもんであって。
誰も「普通の東大生数百人のレベルをギリギリにチューンする」なんて言ってないし、そもそも東大生の中で「教育制度がもっとよければ俺はもっと偉くなれた!」なんて言ってる奴は落ちこぼれだけだよ。だから「普通の東大生数百人のレベルをギリギリにチューンする」という発想自体がそもそも無意味。
いや、お前そういう話しかしてなかったじゃんw 俺が公教育は平均と底辺を上げるためのものだと主張したらやたら激しく反発してたよなあ?
主流と標準を辞書で引くことをお勧めする。そりゃ、主流が標準を塗り替えてしまうことは結構あるが、少なくとも数値計算の世界ではまだだろう。過去の蓄積ってのがあるんだ。
Cを使ってアセンブラまがいのコードを書き、新しい言語なんて覚える暇があったらもっと他のことをするとかなんとか言ってる人だって一定の比率で存在する。おわかり?
それは、特にアセンブラが必要でもないケースでか? ちょっと勘弁して欲しいなw まあ仕事としてうまくやれてるならそれでもいいけどさ、特殊ケースだろ?
まだ、例えば専用プロセッサなり組み込みデバイスなりを制御するためにアセンブラ使うってほうがはるかに一般的なケースだと思うがな。数値計算やパターン認識においてさえ。
どうも話が巧妙にずらされてる気がするんだが。
いや、君自身RubyとかPerlとかC++とかJavaとかに言及しちゃったからねえ。どっちが引っ掛けたかというのは不毛になりそうだからやめようや。なんなら俺がズルかったということにしてもいいが。
たとえばいきなりJavaを覚えさせられた人間がそれがわかるとは到底思えない。ライブラリのソースを読めるレベルになってはじめてわかることだろう、それは。
いや、Javaのライブラリのソースを読むレベルになったらたしかにかなり専門的だが、そもそもJavaで書いたコードで高速計算させようというほうが間違いなわけで。
C++に関して言うなら、アセンブラ的な最適化に手を出すのはだいたい最後の最後だろう。俺(や多分君)のような古い世代はアセンブラからの積み上げで高級言語を見るけど、高級言語の側から必要なレベルまで掘り下げていく、という見方も可能なはずだし、最適化の上ではむしろそちらが本筋。
で、君が重いクラスライブラリとして想定してるのはなんなの? ちゃんと最近のものを使ってれば、そんじょそこらの奴がCでちゃっちゃと書くコードと同じかたいていは速いコードを生成するし、もちろん可読性も高くなるな。
C++の話も同様。敢えて「C++らしい」処理を書けば計算量はどんどん増えて、例えば行列をカプセル化して演算子をオーバーロードしてなんてことやってたら計算時間が倍ぐらいになってもおかしくはないだろう。一晩で終わる計算が翌日の昼までかかるということになったら作業効率には歴然たる差が出るぞ。
具体的にどこの出してるC++用行列演算ライブラリがそこまで効率悪いって?
(補足追記)
最近のC++用の数値演算ライブラリはかなり出来がよく、FORTRAN用のそれに性能で肉薄するところまで来ている。そう、ここでは、ライバルは君が主流からも標準からも蹴落とされたと主張したいらしきFORTRANなんだよ。
で、どの辺がネックかというと、君の言うように記述性と実行速度の関係だったりはする。でも、それは低水準処理がどうこうという問題ではないよな。
この件については、議論してる人がネットでも結構いるから読んでみるといい。君が思うほどにC,C++が圧勝しているわけではないよ。随分C++が向上してはいるけど。で、FORTRANのほうが言語の構造上最適化が効き易い等の話題はあっても、手作業で機械語レベルの最適化をするなんてのは、候補にさえ挙がらないな。
あのさあ、「一般的にはこういうことが言われている」ということを主張したら、いつの間にか俺が「こういうこと」を主張していることになってるのはなんでなんですか、とさっきから何度も聞いてるんですが。「そうとしか思えないから」って、あんたの主観でしょ。しかもあんたが俺のことを色眼鏡で見てたことはあんたが自分で言ったことだし。
ほう、その辺の本には「神」なんて言葉が乱舞しとるがな。じゃあ日本の古典がどう宗教的価値に直結しとるんだ?
これは確かに読み飛ばした、失敬。
日本の古典の話をしてるんだが。とりあえず便宜的に日本の言文一致体以前以後で区切ってみようか。
なんか、今でも一般人が学ぶ意義のあるような文献がそれ以前にある?
しつこいなあ。食い下がってるのはどっちだよ。「意義」の定義によるだろ。「一般人レベル」でいうのなら、欧米先進国様の古典を学ぶ意義と同程度のものは間違いなくあるよ。日本文化のうち文学と美術と舞台芸術に優れたものがあることは君も否定せんだろうが、それらの趣味が思想だのなんだのに劣ることはあり得まい。
グレコ・ローマン文化の話じゃなかったのかよ。近代以降ならそりゃ当然だろ。フランス革命1789年と明治維新1868年の差が今更どれほど重要だとあんたが思ってるのかは知らんが(明治維新は不完全な革命とかいうなよ。そんなこと言えばロベスピエールとかナポレオンってのはどうなるんだ)。ただその意味で言うなら欧米であってもドイツなんかは後進国なんであって、あんたが言ってるのは「イギリスとフランス」の話でしかない。「欧米」ではないぞ。
君の言うステータスシンボルのような意味での「役に立つ」自体を俺は批判し否定してるんだよ。まやかしだってな。で、撤回したんじゃなかったか? やっぱ食いさがってんじゃんww
ほら、君は「??だとすれば」という仮定が読めないんだよね。背理法とか理解できてないんじゃないの?出来の悪い中学生とかで、「もし√2=p/qと既約分数で書けたとするとpもqも偶数になるが」とかいうと、「pもqも偶数なわけないだろ!」とか言って聞かないガキがいるよね。
あとさあ、まやかしはまやかしで構わないけど、そういう意味なら俺は英語の「役に立つ」もまやかしだと思うがねえ。
とりあえず、「まやかし」と「役に立つ」をあんたはどういう基準で使い分けてるのか明示してくれ。でないと話にならん。
えーと、そういう主張をしたいのならまずソースよろ。
はあ?何のソースだよ。俺は君の主張を自然に演繹しただけであって、敢えて言うならソースは君の発言だが。
東大卒は毎年数千人だ。それで、MIT卒は何人いるか知ってる?ハーバードは?プリンストンは?スタンフォードは?オックスフォードは?ケンブリッジは?
本当に新天地を切り開くようなエリートってのは、せいぜい数人程度だろ。その数人にどういう教育をするかと考えた場合、国内でまかなおうなどと無駄な縄張り意識を発揮するよりは、とりあえず世界トップレベルの大学に送り込めばいいんじゃないの、と。
天才信仰ですか。まあいいや。仮にそうだとしても、「年に数人」レベルの人間に「教育」なんておこがましいと思わんか。そんな人間はほっといても自分に最適な場所を探してくるし、そこが日本である可能性もあれば海外である可能性もある。
国を背負うほどのものでもない普通の東大生数百人のレベルをギリギリにチューンすることに金を使うよりは、普通の大学を出る普通の何万人のレベルを上げるほうが安上がりだし価値があるんじゃねえの、と。
誰も「普通の東大生数百人のレベルをギリギリにチューンする」なんて言ってないし、そもそも東大生の中で「教育制度がもっとよければ俺はもっと偉くなれた!」なんて言ってる奴は落ちこぼれだけだよ。だから「普通の東大生数百人のレベルをギリギリにチューンする」という発想自体がそもそも無意味。
いや、主流の座から滑り落ちたものを普通はスタンダードとは呼ばないだろう。そう言えるからには、後続のものがスタンダードを一つの目標に据えて設計されたとかそういう事情が必要だ。ちなみに釘をさしておくが、別にこの主張に固執するつもりはないから反論は不要。否定してくれてかまわん。
でも、コアの計算部分がライブラリに分離されちゃうケースが増えると、ますます低水準処理がどうこういう意味がなくなるような。
出来合いのライブラリを使ってない研究者だって沢山いるし、そもそも計算アルゴリズム自体に工夫をする人だっているわけでな。その辺は計算の規模と計算機リソースの兼ね合いと、あるいは本人が計算機を好きか嫌いかなんていう、実に卑近な事情によって決まってくる。それこそ情報工学の研究者であっても、俺が例に挙げたパターン認識や待ち行列の研究者の中には計算機の実践的側面なんかに興味がなく、Cを使ってアセンブラまがいのコードを書き、新しい言語なんて覚える暇があったらもっと他のことをするとかなんとか言ってる人だって一定の比率で存在する。おわかり?あんたの言ってる「情報工学」は「コンピュータ工学」でしかないことに気付いてほしいな、いい加減に。そこだけ理解してもらえればあとはどうでもいい。そうすれば、あんたが噛み付いてる点自体が枝葉末節だってことにも気付くだろうし。
前にも書いて綺麗に見ない振りされたけど、それ言語の選択と無関係だよね。
<<
元々の話覚えてるか?「低レベル寄りの言語を知識としてだけでも知らない人間に」云々という話だっただろう。どうも話が巧妙にずらされてる気がするんだが。たとえばいきなりJavaを覚えさせられた人間がそれがわかるとは到底思えない。ライブラリのソースを読めるレベルになってはじめてわかることだろう、それは。
C++の話も同様。敢えて「C++らしい」処理を書けば計算量はどんどん増えて、例えば行列をカプセル化して演算子をオーバーロードしてなんてことやってたら計算時間が倍ぐらいになってもおかしくはないだろう。一晩で終わる計算が翌日の昼までかかるということになったら作業効率には歴然たる差が出るぞ。
しかし、OOPは各オブジェクトの構造や関連に注目した記述となるため、自然言語との親和性が手続き型よりも低い。オブジェクト指向は視覚的なアプローチなのに対し、手続き型言語は言葉による理解。一昔前の言葉で言えば、ランダムアクセスとシーケンシャルアクセス並の違いがある。
OOPが人間界、、、人間の世界観に沿っているのは同意するが、人間の言葉に合わせているのではない。
また、「xxx.doThat()」を羅列しただけのようなプログラムはOOPではない。それは手続き型だ。
ちなみに俺はOOPの利点は、メソッド・変数群の名前空間の整理(大規模プログラムを書いても名前が混乱しにくい)、データのカプセル化(複数の違うフォーマットのデータを同じもののように扱える。多態性)であると思っている。分析との親和性についてはオブジェクトもデータフローもペトリネットも大して差がない。
いや、なんていうか覚え立ての言葉をいろいろ使ってみたかっただけだ、すまん。
gdgdっぽいけど反論しておくと、超巨大画像云々はあくまで例です。
メモリ連続云々は、ミップマップ構築等で横方向だけでなく縦方向のアクセスも行われるとき、巨大な画像だとメモリアクセスがキャッシュにうまくのらず酷いことになるという話。
それはともかくとして、カプセル化することによって内部実装を隠蔽し、変更可能にするというのはオブジェクト指向の大きなメリットだと思うのだけれど。
趣味で作る規模のプログラムでは内部実装さらけ出し状態でもあまり問題にならないということかな?確かに大学のレポート提出用のプログラムをC++で組んだ為にCで素直に組んだ場合と比べて非常に冗長になってしまった覚えはあるが。
オブジェクト指向が人間らしい書き方かには疑問の余地があるが、C言語とかでプログラミングしてると必然的に行き着く考え方だとは思う。
オブジェクト指向ではない世界で、自分で設計しながらプログラミングした経験があるとオブジェクト指向の理解って早いんだよな。最初からオブジェクト指向ありきの書き方を教えちゃうと、その必然性が理解できないから、ついていけない人が発生する。
趣味でプログラミングをやっていた人間と、そうでない人間の差はここに生まれる。必要に迫られたプログラミングしか経験していない人は最短距離しか進まないから、試行錯誤の末に先人の叡智と同じ結論に自分で達した人とは、理解の深さが違ってくる。
http://anond.hatelabo.jp/20070429155517
えー、IME 任せは微妙だなあ。めんどくさくてもオンオフぐらいしようよ。状況に応じた大文字小文字の選択もしづらい(できない?)し微妙だよ。少なくともそういう入力方法を叩くプログラマーは少なくないと思う。
19世紀はgoto文の時代だと思ってましたよ。
goto文不要論なんてもう何十年も議論され続けてるよ。大体 90年代終盤にはそこそこ普及してた Java は既に goto が実装されてなかったでしょ。今でも実装されないままだし。
それから Amazon.co.jp で「オブジェクト指向」を検索して「出版年月日が新しい順番」にソートして一番ケツに飛ぶと 80年代のオブジェクト指向本なんて山程出てくる。
というかあまりオブジェクト指向のプログラムってみたことないかも。
なんかこのご時世におすすめないかな?
学生さんかなんかかな。もしオブジェクト指向の利点がまだ理解できてないなら、この話の増田ツリーのどっかにあったと思うけど、
ぐらいの経緯を辿ればまあオブジェクト指向の基本は掴めると思う。当然ある程度の大きさのプログラム(あんまり行数で言いたくないけど、せめて 1000行以上)を書かないと、各プロセスの絶望を知ることはできないと思うけど。必要は発明の母。あとは平行して適当に Amazon.co.jp で評価のいい本を読めばいい。
インターフェイスの概念については、一般に知られているものだと C のストリームで理解できると思う。
FILE *fp; fp = fopen("log.txt", "w"); fprintf(fp, "Starting log...\n"); fclose(fp);
これは log.txt ってファイルにログを吐いてるのね。でも fprintf() ってのは次のような使い方もできる。
fprintf(stdout, "Starting log...\n");
stdout ってのは標準出力で、そこに fprintf でデータを渡すと(Windows の場合)コマンドプロンプトに文字列を表示する。ファイルと標準出力は全く違うものだけど、インターフェイスが同じだから全く同じように出力処理を書けてるでしょ。これを発展させれば、
FILE *stream; if (log_kind == LOG_FILE) { stream == fopen("log.txt", "w"); } else if (log_kind == LOG_STDOUT) { stream == stdout; } fprintf(stream, "Starting log...\n"); /* この時点で stream の種類を知る必要が無い! */ if (log_kind == LOG_FILE) { fclose(stream); }
と書くことができる。年賀状と大学受験合格通知は違うものだけど、初期化(書き方)が違うだけでインターフェイス(ポストに投函)は同じ、みたいな。それよりよく考えたら C を知ってるとは限らんよな。めんどくさくなってきた。あとはしりません。