2023年11月10日金曜日

プログラミングをしていく中でなぜオブジェクト指向的な考え方が重要なのでしょうか?

https://jp.quora.com/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%82%92%E3%81%97%E3%81%A6%E3%81%84%E3%81%8F%E4%B8%AD%E3%81%A7%E3%81%AA%E3%81%9C%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87

石塚 正浩さんのプロフィール写真
石塚 正浩
さん、この質問に回答してみませんか?
並べ替え
 · 
フォロー

「オブジェクト指向」自体が様々な解釈をされ、その指すものが各自バラバラなのでなんとも言い難いところがありますが、自分なりの答えを。

ちなみに自分は言語的にはObjective-C、Java、Rubyあたりを意識していて(あとSmalltalkは使ったことないけど先駆者として)、C++には否定的です。

質問の答えを一言でいうと、構造化プログラミングだけでは不十分だからです。

構造化プログラミングと、オブジェクト指向プログラミングの一番の違いは、ここで書いたように、メソッドを動的に解決するか否かだと考えています。C++はデフォルトが静的であることが他の言語と大きく違う点です。

この違いは呼び出しメソッドを「静的」に解決するか、それとも「動的」に解決するかの違いです。静的に解決するなら単にポインタの加減算で済みますが、動的に解決する場合は仮想関数テーブルの検索が必要です。

Hideki Ikemoto
 · 10月5日
コードがC ++エンジンによって解釈/実行される場合、Ruby、Python、JSがC ++よりも遅いのはなぜですか?
ChatGPTに作ってもらったコードですが、例えばC++の場合、次のように new Dog() としても、Animalとして定義されていたら、Animalのメソッドを呼び出します。 #include <iostream> class Animal { public: void makeSound() { std::cout << "Animal sound\n"; } }; class Dog : public Animal { public: void makeSound() { std::cout << "Woof!\n"; } }; int main() { Animal* a = new Dog(); a->makeSound(); // Output: Animal sound! return 0; } 他の多くの言語ではこのようになりません。Javaの場合はこうなり、 class Animal { public void makeSound() { System.out.println("Animal sound"); } } class Dog extends Animal { public void makeSound() { System.out.println("Woof!"); } } public class Main { public static void main(String[] args) { Animal a1 = new Dog(); a1.makeSound(); // Output: Woof! } } Rubyの場合も同様、 class Animal def make_sound puts "Animal sound" end end class Dog < Animal def make_sound puts "Woof!" end end a1 = Dog.new a1.make_sound # Output: Woof! Pythonの場合も同様、 class Animal: def make_sound(self): print("Animal sound") class Dog(Animal): def make_sound(self): print("Woof!") a1 = Dog() a1.make_sound() # Output: Woof! JavaScriptの場合も同様です。 class Animal { makeSound() { console.log("Animal sound"); } } class Dog extends Animal { makeSound() { console.log("Woof!"); } } const a1 = new Dog(); a1.makeSound(); // Output: Woof! C++で他の言語と同様に処理するためには、virtualキーワードを使います。 #include <iostream> class Animal { public: virtual void makeSound() { std::cout << "Animal sound\n"; } }; class Dog : public Animal { public: void makeSound() { std::cout << "Woof!\n"; } }; int main() { Animal* a = new Dog(); a->makeSound(); // Output: Woof! return 0; } 速度を比較するためにこのvirtualありなしを1000000000回呼び出すプログラムを最適化オプション-O3付きでコンパイルすると、次のような結果になりました。単純計算すると数百倍の差があります。 * virtualなし: 0.005秒 * virtualあり: 2.1秒 この違いは呼び出しメソッドを「静的」に解決するか、それとも「動的」に解決するかの違いです。静的に解決するなら単にポインタの加減算で済みますが、動的に解決する場合は仮想関数テーブルの検索が必要です。 速度的には僅かの差かもしれないですが、これが一番本質的な差だと思います。 ここで挙げたJava、Ruby、Python、JavaScriptのように多くの言語は動的に解決しますが、それはその方が柔軟で扱いやすいからです。その意味ではC++は「デフォルトでは静的だが、動的にもできる言語」とも捉えられます。 一方で例えばObjective-Cはデフォルトは動的呼び出しですが、IMP呼び出しと呼ばれる手法があり、繰り返し処理する場合に高速化できます。 IMP呼びだし 毎回メッセージパッシングを行なう代わりに、一度だけメソッドを解決して関数ポインタを取り出し、メソッドの呼び出しを高速化する技法。呼びだしコストが通常のC関数と等しくなる。俗にインライン化とも呼ばれる。

もし動的かどうかではなく、単にデータと紐づくメソッドの存在だけなら、抽象データ型という概念になります。

この抽象データ型は文法こそオブジェクト指向プログラミング言語と同様ですし、重要な要素ではありますが、これだけなら概念的には構造化プログラミングの範囲に留まります。

抽象データ型 - Wikipedia
出典: フリー百科事典『ウィキペディア(Wikipedia)』 出典 は列挙するだけでなく、 脚注 などを用いて どの記述の情報源であるかを明記 してください。 記事の 信頼性向上 にご協力をお願いいたします。 ( 2022年5月 ) 抽象データ型 (ちゅうしょうデータがた、 英 : abstract data type 、ADT)とは、データ構造とその操作手続きを定義した データ型 、またはデータ抽象 [注釈 1] の方法の1つ。通常のデータ型であれば変数宣言で変数に束縛されるものは値であるが、抽象データ型の世界において値に相当するものはデータ構造とその操作 [注釈 2] のまとまり [注釈 3] である。 抽象データ型を用いない場合、データ構造またはデータの操作手続きのアルゴリズムの変更を行うとソースコード中にその変更部分が散在してしまい規模によっては修正困難となるが、データとその操作がひとまとめに記載されることになる抽象データ型においては、型の定義における実装部分を変更するだけで修正が完了する。 1960年代の 構造化プログラミング の時点で既に、(よく知られている)段階的詳細化といった手法や 制御構造 の利用の励行などの他、データ構造とコードを連携させ、データ構造の変更を行うと変更部分がソースコード中に散在してしまうというそれ以前のプログラミングにおける問題点への対処にもなる、データ抽象に関する議論は現れている(『構造化プログラミング』(日本版はサイエンス社、1975年)の、全体の約半分は ダイクストラ による考察だが、残り約半分は ホーア と ダール ( Simula の設計者)によるデータ論である)。抽象データ型はデータ抽象の具体的手法として1974年に バーバラ・リスコフ の提案した言語 CLU において提案された。 インタフェースと実装の分離 [ 編集 ] プログラムが実装されたとき、抽象データ型は実装を隠蔽するインタフェースを表す。実装は将来において変更されうるので、抽象データ型のユーザーは実装ではなくインタフェースに関心がある。 抽象データ型の強みはユーザーから実装が隠蔽されていることである。インタフェースのみが公開されるのである。このことは、抽象データ型がいろいろな方法で実装されうることを意味するが、インタフェースに忠実な限りユーザープログラムは影響を受けないのである。 例えば、二分探索木抽象データ型はいくつかの方法で実装できる。例えば、 二分木 、 AVL木 、 赤黒木 、配列である。しかし実装に関わらず二分探索木は「挿入」「削除」「検索」といった同じ操作が可能である。 抽象データ構造 [ 編集 ] 抽象データ構造 とは、実際の データ構造 による実装に関わらず、操作の集合とその 計算量 により定義されるデータのための抽象的な領域のことである。 具体的なデータ構造の選択がアルゴリズムの効率的な実装にとって重要である一方、抽象データ構造の選択は効率的なアルゴリズムの設計とその計算量の推定にとって極めて重要である。 この概念はプログラミング言語の理論で用いられる抽象データ型の概念に非常に近い。多くの抽象データ構造や抽象データ型の名前は具体的なデータ構造の名前と一致する。 具体例 [ 編集 ] 抽象データ型としての有理数 [ 編集 ] 有理数 は計算機においてはそのまま扱うことはできない。有理数の抽象データ型は以下のように定義できる。 コンストラクタ : 2つの整数 a {\displaystyle a} 、 b {\displaystyle b} を用いて有理数の抽象データ型のインスタンスを作成する。ここで a {\displaystyle a} は分子で b {\displaystyle b} は分母である。 関数 : 加算,減算,乗算,除算,指数計算,比較,約分,実数への変換 完全な記述にするためには、それぞれの関数はデータに言及して記述されるべきである。例えば、有理数 a / b {\displaystyle a/b} と c / d {\displaystyle c/d} を乗算するときには結果は a c / b d {\displaystyle ac/bd} と定義される。通常は入力、出力、実行前条件、実行後条件、抽象データ型に対する仮定も記述される。 ^ データ抽象( 英 : data abstraction )とは、データ型の詳細定義とその操作に関する手続きを情報の局所性が高まるようにソースコード中の一カ所にまとめて記述するための記法のことを言う。情報が一カ所に局所的にまとめて記載されているため、非公開(private)部分の変更であればその定義部分の詳細を変更するだけでソースコード全体の修正が完了する。 データ型の詳細定義とその操作手続きの局所的記述を実現する方法は複数あり、抽象データ型はその一例である。 ^ 言語に応じて名称が異なり、 C++ であればメンバ関数(member function)、 Java であればメソッド(method)と呼ばれる ^ データ型の値に相当するこのまとまりのことを抽象データ型の実体(インスタンス , instance)と呼ぶ。 参考文献 [ 編集 ] 落水 浩一郎『ソフトウェア工学実践の基礎 -分析・設計・プログラミング』日科技連出版社、1993年。 飯泉 純子, 大槻 繁『 ずっと受けたかったソフトウェア設計の授業 』翔泳社 。 https://books.google.co.jp/books?id=gJhtVWzM4BsC&printsec=frontcover&hl=ja&sa=X&ei=Z4ubUf_NL43mkgWD1YGoDQ&ved=0CDwQ6AEwAA*v=onepage&q&f=false 。 D.L.Parnas (1975), Use of the concept of transparency in the design of hierarchically structured systems , http://ivizlab.sfu.ca/arya/Papers/SW/TranspDesignHierSys.pdf D.L.Parnas (1971), Information Distribution Aspects of Design Methodology , http://cseweb.ucsd.edu/~wgg/CSE218/Parnas-IFIP71-information-distribution.PDF B.H.Liskov, S.N.Zilles (1974), Programming with Abstract Data Type , http://www.znu.ac.ir/members/afsharchim/lectures/p50-liskov.pdf Niklaus Wirth (1971), Program Development by Stepwise Refinement , Communications of the ACM, Vol. 14, No.

そしてもし、ひたすらトップダ

… (もっと読む)
 · 
フォロー

層による構造化がないと複雑なことを実現しにくいからです。

コンピュータがモデル化するドメイン、および、コンピュータが実現する機能というのは、層を成す複雑な構造をしています。

層化して問題を捉えることで、他の層は他人の仕事に頼ることができ、自分が担う層の実装だけに注力することができます。層化というアプローチはプログラミングの常道 Divide and Conquer の1種です。

この多層構造での設計・実装に適した表現の1つがオブジェクト指向なのです。

Niwa Yosuke
 · 2月14日
オブジェクト指向のプログラミングって何で必要なんですか?
ここに似たようなことを回答として書きました。 これはオブジェクト指向でプログラミングする必要がある!と思う場合は、どんなアルゴリズムを作ろうとした時でしょうか?に対するNiwa Yosukeさんの回答 オブジェクト指向は階層構造による情報整理手法です。 整理するほど情報がないなら別にオブジェクト指向を持ち出さなくてもいいです。しかし、コードを数百行ほど書いたら普通は整理したくなります。 オブジェクト指向が必要なのは、階層構造を作らないとどこに何があるかわかりにくくなるからです。大規模開発でコードが数万行にもなるケースでは、オブジェクト指向がないと管理できず破綻します。 C++ / Java / C# などのオブジェクト指向言語における class は C 言語の struct に端を発しています。struct はプリミティブなデータ型 (int, long, double 等) をいくつか集めてひとまとめにパックしたものです。 C 言語においては、struct を単位としてネストさせ、struct を含む struct を含む struct … と階層構造にすることで複雑なデータセットを構成でき、structA.structB.structC というように "." を連ねることで階層内の目標とする対象へ直感的にたどり着ける便利なアクセス記法を用いる仕様になっています。 パックしたデータはそれぞれ意味を持っている (= 意味単位にデータをパックする) ため、そのデータセットに適用する関数も抱き合わせで近くに置いておきましょうという発想で、データセット/変数群だけでなく関数をもパック単位に包含するように struct を拡張したのが C++ 以降の class です。 その上で、せっかくデータをわかりやすくパックしたのだから、C 言語のようにフラットに置かれた関数にこまごまとした複数のプリミティブ型データを適用するのではなく、パックしたデータセットの方へそのデータセットに相応しい関数を適用する、というように発想を転換します。データと関数の主客を逆転させ、まとまりとして意味を持つデータセット (= オブジェクト) の方を主軸に据えるため「オブジェクト指向」と呼ばれます。 オブジェクト指向プログラミングには「継承・多態性 (ポリモーフィズム)」「is-a (派生) 関係と has-a (内包) 関係 」「契約と実装の分離」「オーバーライドとオーバーロード」「差分プログラミング」等々の概念やテクニックがありますし、凝り始めるとデザインパターンなどの難しい抽象化にハマっていくことになりますが、そのような難しく抽象的な側面から説明を始めるから、初心者は混乱してオブジェクト指向の目的や意味を見失うのだと私は思います。 オブジェクト指向の本質は単なる「階層構造による整理」であり、加えて「各階層やその中身にアクセス権を割り振る」ということをするだけです。ファイル管理とまったく同じです。 大量のファイルを扱う場合、意味単位別にフォルダを掘って、その中にファイルを格納し、アクセス権を設定する。深い階層には Layer01/Layer02/Layer03 という記法でアクセスする。 それと同様に、大量の変数や関数を扱う場合、意味単位別にクラスを掘って、その中にメンバー(変数、関数)を格納し、アクセス権を設定する。深い階層には Layer01.Layer02.Layer03 という記法でアクセスする。 ただそれだけのことです。
 · 
フォロー

現実世界は複雑です。これをそのままコンピュータの世界に表現するのは難しい。

そこで、コンピュータが管理しやすい状態に、データ構造に着目して抽象化するのがオブジェクト指向です。

事象を抽象化したのがモデル。

モデルを抽象化したのがオブジェクト。

コンピュータにとって都合のよい状態にしてるので、プログラミングにおいても当然有意です。


余談

オブジェクト指向の特徴の1つに継承があり、継承を多用すると分かりづらいとか言われますが、それは設計したやつが悪いだけで、オブジェクト指向そのものの問題ではない。

 · 
フォロー

人間が機械を動かすための「プログラム」を作るにあたり、

考えのまとめ方(分析、設計)、データの管理方法、処理の管理方法、として

かなり人間の考え方に親和性が有ったから、使いやすい方法のひとつ

であるためです。

そこにたどり着くまでに、色々な方法が発明され、悪い発展も良い発展もして、誤解もされ、

そして現在ではある意味「オブジェクト指向はもう古い」とばかりの言説を聞くようになりました。

しかし、その言説も、オブジェクト指向に基づく分析手法、実装手法に基づいているがゆえに、オブジェクト指向がある程度わからないとさっぱり理解もできません。

そういう意味では、どのようなプログラム言語でも、オブジェクト指向を全部綺麗さっぱり捨て去ることなどまだできませんし、こんにちにおけるマシン語くらいの立ち位置できっと未来永劫、少なくとも10年は、生き残ることでしょう。

 · 
フォロー

オブジェクト指向的な考え方というのは、「餅は餅屋に任せる」という発想ですね。これに対して手続き型は、プログラマという全知全能の神がいるイメージです。

プログラムが大規模になると、神に要求される能力はどんどん膨らんでいきます。そして規模が大きくなり過ぎると、ある日パチンと弾けて破綻してしまいます。

会社で言えば、ワンマン社長と任せる社長の違いですね。大企業はおしなべて後者になります。

 · 
フォロー

Windows APIの設計手法がまさにそれですね。C言語で実装されていますが、考え方はオブジェクト指向ですよね。 HWND, HANDLE などのvoidポインタで実装し、ハンドルという抽象的なコンテキストオブジェクトを介して操作をするという統一性を実現しています。細かい箇所まで行き届かないのは仕方ないとしても、大筋ではその流れで考えればどの機能も同じように実装していく事が可能です。

オブジェクト指向的な考えが重要なのは
「ひとつ理解すれば芋づる式に同じように考えられて理解が早まる」という事ではないでしょうか

特定言語の「オブジェクト指向仕様」に縛られて洗脳される前にそれとは別にこういう考え方で統一する便利ですよね。という非常にシンプルな話だと私は思います。

 · 
フォロー

可読性が向上するのも一つの利点です。

 · 
フォロー

いろんなプログラミング言語はオブジェクト指向のパラダイムを言語の仕様に取り込んでいるからです。

なので、そういう言語を使う場合においては、オブジェクト指向的な考えができないと、「話にならない」んですね。

 · 
フォロー

同じことをやるやつをいろんなところに書いてあるとなにかあったときに直すの面倒でしょ、と言うのがひとつ。

あとデータをごにょごにょしてプログラムは動くのでデータ主体で考えて、データに「これやって、あれやって」ってかいたほうが自然じゃない?というのがひとつ。

じゃ、データごとにやることをまとめたほうがいいよね(1番目の考え方)、データも関係あるのをまとめておいたほうがいいよねって言うのがオブジェクト指向の元々の考え方(2番目はActor的な考え方)

多分異論はあると思うので私はこう思っているということで。

流行りだからでしょうね。

30年くらい前からブームが続いていてこの10年で少し落ち着いてきた印象があります。

30年前頃C++が脚光を浴びて、オブジェクト指向を哲学のように扱った大仰な解説記事が10年以上作られ続けました。

初期の頃はオブジェクト指向というと継承がもっともその特徴を表した機能としてもてはやされ、入門書の最初の解説に継承を持ってくるものだからやたらめったら継承を使いたがる人が増えました。それでいてもてはやされているから批判されない。批判したら無能の烙印を押されかねない状況が続いていたと思います。(最近はそんなことはなく、この10年で一番変わったところだと思う)なぜ継承批判が許され始めたのかと言えば、今は継承を持たないオブジェクト指向言語がトレンドになってきているからでしょう。だから今後継承を使うと逆に批判されかねない時代に突入するかもしれません。

継承の影響が大きいと思いますが、オブジェクト指向を高尚なものとして論じるムードになった理由は、「よく解らないから」だと思います。解ってない人が解ったふりして論じてそれを読んだ人が解った気になってまた論じて解らないところは勝手解釈で論じて煙に巻く。そういう歴史が積み重なっていつまでたっても解かりにくいモノ扱いになっているのが現状に思います。

オブジェクト指向を簡単に説明するとwindowsのフォルダを右クリックしたらプルダウンメニューが出てきますが、あれは正にオブジェクト指向の操作です。右クリックで出てくる機能リストはそのフォルダ(=オブジェクト)に対して機能するということは明白でしょう。非常にわかりやすい操作性です。

作り方からオブジェクト指向を学ぶ方法は「継承とは」で検索するとたくさん見つかると思います。(基底クラスやスーパークラスの意味を正反対に解釈している物も多く結構問題あります)系統立てて分類していると何か仕事をしている達成感がありますが、分類が目的に案外なりがちです。やってみると誰もが陥る罠だと思いますが、信者は罠に落ちているのではなく無知蒙昧な輩はまだ英知に触れていないと考えがちなので頭痛いですね。

オブジェクト指向はsmalltalkという言語(OSと一体となっている言語)が原点にあり、本来はGUIと結構密接に関係します。C++以降、言語とOS(GUI)を分離したことで直感的にイメージしにくい概念になってしまったのだと個人的には思います。

でも先ほどのプルダウンメニューの例で考えたら、オブジェクト指向でプログラムを組むメリットが解りやすいんじゃないでしょうか?ちなみにこの例えはWindows95のプロトタイプを作った中島聡さんがされていたものです。

ところで日本語もオブジェクト指向的だと言われます。英語だと、SVOという文法に現れているように目的格(オブジェクトのOですね)が最後に来る文章でも、日本語だと目的格を最初にもってきて叙述する形で表現することが多いです。だからオブジェクト指向はむしろ日本人には考えやすい概念なのではないでしょうか。

広告
 · 
フォロー

重要になる局面もありますが、必須ではないですよね。強いて言えばオブジェクト指向をベースとしたプログラミング言語を使う場合はそうなりますかね。

オブジェクト指向は唐突に出てきた考えではなく、プログラミング黎明期から連綿と培われ、構造化プログラミングの先にある技術と言えましょう。また、「オブジェクト指向」と言っても発案当初と現在では扱いもポジションも変わってきています。

そういった意味で勉強しておくといいとは思いますが、できればその他の技術もさらっておく方がなにかとよろしいかと。

 · 
フォロー

いろいろありますが、オブジェクト指向で上手に設計すると、データと操作をカプセル化する事により、プログラム構造全体の複雑性を緩和する事ができます。ソフトウェアエンジニアリングはソフトウェアの複雑性をコントロールするための技術領域ですが。オブジェクト指向プログラミングはこの用途に対して有効な方法の一つです。

 · 
フォロー

オブジェクト指向って(メソッドだけでなく)データを中に包含するような考え方ですが、一方でデータはいまではほぼDB上にあります。

じゃDBから該当するデータをぜんぶオブジェクトに持って来ていいのかというと、マルチユーザマルチタスクのシステムを実現するときにそんなことをやったら大量のデータを読み取り、さらにそれをロックしないといけなかったりします。オブジェクト指向に従ったプログラムを大量に作成し、そのおかげで全く動かなくなったシステムが実際にありましたよ。2012年頃少なくとも5億円がドブに捨てられました。教科書みたいなものを鵜呑みにして自分が担当するプログラムの都合しか考えずにシステムを作ると、全然動かないシステムになります。

データを集中管理するDBとオブジェクト指向プログラムとは相反する考え方だったりするので、オブジェクト指向も注意して開発しないとこういうことになります。当然のことながら、プログラム1個でも同時アクセスしうるテーブルをロックする時間が長いと他に影響します。ロックの時間を最小にするような設計をひとつひとつのプログラムで心がけないと、即、動かないシステムになります。

 · 
フォロー

重要ではなく、発見でしょう。こういう考え方をすれば、プログラムは、ドラスティックに変わる、いや画期的だという発見です。

わたしは、オブジェクト指向は、革命だと思っています。オブジェクト指向革命です。

 · 
フォロー

発注者の大多数は素人(私も)なので、説明時のクライアント側を理解させる際には容易になるような。。

 · 
フォロー

オブジェクト指向的なアプローチでプログラミングをすることがほとんどですが、その考え方が重要だという風に思ったことがありません。

オブジェクト指向でプログラミングをした方が楽だからです。なぜ楽なのかというと現実世界をプログラミングに落とし込みやすいと感じるからです。

仕事上で業務支援のプログラミングをするので、その内容はデータ処理が大半を占めます。データ処理の観点だと構造化プログラミングや関数型プログラミングがマッチするのでそれを使います。が、ファイルや部署や人やらという物理的なものも業務にはかかわるので、そういう物理的なものや概念とかルールや規則みたいなものを扱う時もあります。そんな時にはオブジェクト指向のアプローチでプログラミングをします。現実世界で変化があった時、それをプログラミングに反映するのがオブジェクト指向の方が楽なんです私には。

世で議論がよくされる抽象化とか継承の話は「こじれてるなぁ~」なんて思っているので、その部分の考え方が重要だという話だとしたら「そこを重要視しなくてもいいじゃない?」というスタンスです。オブジェクト指向は動物と犬猫猿の関係で説明がなされてから時を経て宗教論争になっちゃった感が。「カプセル化とポリモーフィズムの方が役に立つんじゃない?」とか思ってます。

 · 
フォロー

教科書ではデータとコードを分離できるから優れていると書いてあると思いますがイミフだと思います

結論を言えば、データの整理の仕方が優れているためです。大体同じなんだけれど、微妙に違うんだよね、という処理をまとめるのにこれ以上のものは今のところないからですって言葉で書いても意味不明だと思います。例えばゲームを作っているとして、

C++風仮想コードで書くとこんな感じです

class Actor

{

描画処理

コリジョン処理

体力などのパラメータ

};

class Player : public Actor

{

コントローラ入力処理(プレイヤにしかない)

};

class Enemy : public Actor

{

プレイヤを追いかける処理(エネミーにしかない)

};

こんな感じで、PlayerクラスとEnemyクラスはActorクラスから差分を作れば良いので、生産性が爆上がりします

こうして、作ったPlayerやEnemyをあとは、インスタンスを作ってメインループから呼び出すだけでゲームのできあがり(は言い過ぎですが)

この概念がとにかく素晴らしいのです

 · 
フォロー

ぶっちゃけてしまうと、OSやライブラリや今のプログラム言語がオブジェクト指向開発を前提に作られてるからですね。

何故そうなってるのか?は、オブジェクト指向にはメリットがあって、みんながこぞって採用するからです。

基本的な考え方は共通フレームワーク化する事でコストを削減してるんです。

・同じコードを何度も書かない=継承

・共通化=抽象

・微調整=オーバーロード

・ポリモーフィズム=アクセス共通化

 · 
フォロー

クラスを用いて実現される疑似並列処理がプログラムの再利用にあたって便利だからです。プログラムの組み合わせの幅が広がるからと言い換えてもいいと思います。

例えば、ダイクストラの構造化プログラミングでは、プログラムはフローチャートに翻訳できるものに限定されます。つまり、計算プロセスが単線であるもの限定のプログラム技法なのですが、これの不便な点は、2つ検証済みの異なるプログラムA,Bが与えられたとき、頑張って両機能を提供する新たなプログラムCを実装しようとするときに、単純にプログラムA,Bを結合できない(単純に再利用することができない)というところにあります。

当たり前の話なので分かりにくいかもしれません。フローチャートを想像しながら読んでもらえれば幸いなのですが、あるフローチャートに翻訳できるプログラムAともう一つのフローチャートに翻訳できるプログラムBがあるとして、両機能を提供するプログラムCというのは、その2つのフローチャートを単純にくっつけたものでは「ない」のです。

変数名、関数名の衝突、if文の分岐の必要性などがあるので、整合性を保てるようにかならず手直しする必要があります。つまり、構造化プログラミングはあんまりモジュール性(カプセル化)がよろしくないので、純粋な手続とか関数以外は、分業した上で組み合わせるということがしづらいのです。

一方でクラスの場合は、一般にカプセル化と、呼び出しをしてもプロセスが消滅しないという性質のおかげで、クラスとしてプログラムA,とプログラムBを記述してしまえば、それぞれ独立にオブジェクトを宣言して疑似並列的に実行させることができます。この時、プログラムAとプログラムBで相互に衝突する変数名、関数名などの調整は不要です。

つまり、クラスとしてカプセル化した状態でプログラムを提供してしまえば、中の変数名の衝突とかを気にする必要なしに、そのプログラムを再利用することができるという利点があるのです。これはダイクストラの構造化プログラミングではありえません。

こういうプログラムの再利用性がよいという理由で、クラス機構を持ったプログラミング言語が必要とされているという面があると思います。

広告
 · 
フォロー

生産性が向上するからです。

GCCのo2(緑)とo3(青)オプションで生成されるコードサイズ。

C言語は現時点(2022年)で最小または最速のコードを生成するネイティブ・コンパイラですが、コードサイズと実行速度のバランスは最新のRustの方が優れています。

広告
 · 
フォロー

オブジェクト指向の「流行り」というのは本当にすごかったんですよ。1990年代中盤は、例えばOOPSLA(Object-Oriented Programming, Systems, Languages and Applications: 変な名前ですが、ダジャレ好きな私の知り合いによる命名です)というオブジェクト指向を扱った最高峰の学術会議では、言語の細かな機能の提案などに関する学術的な発表が行われている一方で、巨大な展示会場が併設されて、「オブジェクト指向」をうたう製品を持っている会社が何十社もブースを構え、チュートリアルセッションも大盛況で、参加者が5000人に以上にもなるという、それはそれは大流行りしていたものだったわけです。今でもSIGGRAPHはさらに大きな展示会場付きだったりインストレーション・アートがあったりして大きいですが、OOPSLAもそこまでではないものの似たような雰囲気もありました。

当時のジョークとしては「オブジェクト指向というのは、友達みんながやったことあると言っていて、やってみたらすごく良かったと言ってはいるけれど、本当にやっている子は実はそれほどいないという、高校生がアレについて語っているようなものだ」というものがありました。

「オブジェクト指向」に関する市場規模は90年代よりも現代の方がはるかに大きいわけで、オブジェクト指向は「廃れてきた」というわけではな

… (もっと読む)
 · 
フォロー

関数型プログラミングでも全く同じ説明が可能なので、「オブジェクト指向」の説明になっていない、と反論します。

(関数型プログラミングとオブジェクト指向は相反するものではないですが、オブジェクト指向を取り立てて使わない関数型スタイルも「独立した小さな汎用プログラムを構成部品として組み合わせ」ます)

 · 
フォロー

今現在は、特に難しいとは思いません。

今から20年程前(もうそんなに経つのか・・・)オブジェクト指向が流行り始めた頃に独学で理解しようとしていた時は、オブジェクト指向の良さを体感するのに半年位かかりました。

しかしながら、オブジェクト指向にどっぷり使ってしまった現在では、一体何が難しかったのだろうか・・・と、どんな事で悩んでいたのかを忘れてしまいました。

実は、私は文系卒エンジニアで、社会人になってから初めてプログラミングを始めたのですが、最初は変数の意味・意義すらわからない状態でした。

これも、何故解らなかったのだろうか、を忘れてしまいましたが、何でも取っ掛かりは難しく感じるものなのかなぁ、と、思います。

ここ最近(と言っても数年程)は、関数型プログラミングに触れる機会がしばしばあったのですが、手続き型言語に慣れた私にとっては、やっぱり難しく感じます。

でもまぁ、言語仕様やその背景にある思想を理解できると、技術習得のスピードが飛躍的に上がっていくので、老骨に鞭打って頑張っていこうと思います。

何か締まらない文章ですみません。

 · 
フォロー

他の回答でも述べられていますが、プログラミングの経験が浅い人が、本や雑誌の記事などからトップダウンで、オブジェクト指向はこういう概念であり、こういう設計手法だから、それを適用してプログラムを作ろう、という形では理解できないと思います。

私の場合、プログラミングが向上する過程は、以下の様でした。

  1. 最初はめちゃくちゃなプログラムを作る。
  2. 重複したコードを1つの関数にまとめるようになる。
  3. 関連した変数を構造体にまとめるようになる。
  4. 関数をコードが重複しているかどうかに加えて意味(コンセプト)で作るようになる。構造体を引数とする関数を作るようになる。
  5. 構造体を引数とする関数を、構造体(クラス)のメソッドとして分類、整理するようになる(ここでオブジェクト指向に足を踏み入れる)。
  6. 異なるクラスのオブジェクト間で同じメソッド呼び出しを定義し、使用するようになる(ポリモーフィズムを使う)。

このようにプログラムについて考え、改良していった結果が自然とオブジェクト指向に近づくことになっていました。私はこのような経験からの裏づけがあって初めて、本当にオブジェクト指向を理解できるようになると思います。やがてオブジェクト指向のトップダウンの知識と、経験によるボトムアップのプログラミングが1つになれば、オブジェクト指向マスターだと思います。

そうなるには時間が必要です。普通は2年くらいかかるでしょうか。もっとかもしれません。

… (もっと読む)
 · 
フォロー

ここでの「理解」という言葉の定義はなかなか難しいですが、10年近くオブジェクト指向言語を使ったプログラミングを若い方たちに伝えてきた経験から答えてみます。

一般的なオブジェクト指向言語やオブジェクト指向プログラミングの解説は、クラスを定義するところなどから始まることが多いと認識しています。ですが、オブジェクトを使ったプログラミングや他のパラダイムでのきちんと部品化、モジュール化したものを活用したプログラミングにそもそも慣れていない方には、そこから伝えるのはなかなか難しいという実感を持っています。

現在、ぼくがオブジェクト指向プログラミングを伝える際には、まず既存のさまざまなオブジェクトを使ったプログラム(小さなプログラミングでも構わないので)をたくさん作ってもらっています。そして、なんとなく部品の機能を組み合わせてプログラミングしていくことの感触がつかめたかなという段階で、部品を自作する方法を伝え、部品をたくさん作ったり使ったりするのが大変になってきたところで抽象化や多態といった考え方を伝えて、という段階で伝えていくようにしています。

 · 
フォロー

たぶん、オブジエクト指向完全制覇!まるわかり!的な本を100冊読んでも、なかなか理解は難しいと思います。中にはいい本もあるけど、時間をかけた割に、得られた知識とか、知見は驚くほど少なく心が折れて、よくわからないたとえ話が何を意味しているのか理解に苦しむと思います。

GITHUBとかで、コードをひたすら探して、そこから理解するか、これは、いいコードだと言われたものをひたすら読んだり、改造したりする方が理解が早いです。

オブジエクト指向は、変数と関数の整理の仕方についての作法が本質なんだと思います。

 · 
フォロー

以前書いた投稿があります。

オブジェクト指向のプログラミングの問題点は何ですか?に対する山本 聡 (Satoshi Yamamoto)さんの回答

が、その回答は長ったらすぎるので、短めに書くと、

「オブジェクト指向のプログラムは難しいと言われる理由」は、

やれることがいろいろあり、また、それによって起きる制限もいろいろありすぎて、わけがわからない、から、だと思います。

継承だのインターフェースだの多態だのなんだのかんだのといろいろありすぎです。

そしてこれら全てが、どうでもいい概念です。
ifの分岐やforのループや、処理共通化、データを得て、表示を行う。プログラムの重要な概念ってこういうものだけですし、これで多くのアプリケーションの機能を作り出すことができるはずですが、

オブジェクト指向の概念というか、それらの機能はアプリケーションを作るという本質とはかけ離れた機能なので、どう使ったらいいのか本当のところが誰にもわからない、のでアレコレの派閥があってアレコレの議論が行われるので、決まった道がないために学ぶ人は苦労するということになったりします。

自転車置き場の議論として知られる『原子力発電所の建設ミーティングのときに、より重要なことは難しくて議論の対象にはならず発電所の自転車置き場の屋根の色はどうしようかと議論に花が咲く』という例え話がありますが、

オブジェクト指向であーだのこーだの言っているのはこの自転車置き場の議論に近いことが起きます。誰もが大好きな議論ですが、そこにはソフトウェアの機能としての本質はなく、正解もないのでいつまでたっても議論が終わりません。

「クラスごとに纏まっていて見やすいように思えます」というのは

何に対して見やすいのか、ということですが、クラスにまとまるのはグローバルに散らばっているのよりかはマシなのですが、クラスメソッドを書くという時点で、クラスは小さなグローバル領域になっているだけなので、

グローバル変数とかグローバル関数とかだけでアプリケーションを作るのがなかなか困難なのと同じように

アプリケーションが複雑化してクラスがどうしても肥大化しなければいけない時に、一気に複雑さがまして、他人のコードを読むことが困難になるのが、オブジェクト指向です。

クラスの責務がなんたらかんたらと言い出す人もいるのですが、まあ終わらない議論に巻き込まれるだけになりますね。

ということで、副作用がない(あるいは少ない)、参照透過性が高くてテストしやすい関数型プログラミングが流行ってきているようです。

こちらは小さなグローバル領域などは作らないのでアプリケーションの肥大化に対して非常に強く複雑さを隠蔽する仕組みになります。

関数型プログラミングというのも、それなりにあやふやな概念なので議論を呼ぶみたいですが。そのあたりは詳しくないので、どこか他のQuoraで答えをみつけてください。

関数型というか昔ながらの構造化プログラミングですね。

オブジェクト指向を捨てた所に正解があるとは思ってもみませんでした。私、業界20年くらいというかプログラミング歴20年くらいですが、ようやく気が付きました。

ありがたいことに気がついてからは、オブジェクト指向で複雑にからまった状態のプログラムであっても、リファクタリングしたりしてもより簡単なコードをどんどん書けるようになって楽ですよ。

広告
 · 
フォロー

オブジェクト指向の本質は構造化による整理ですから、コードは読みやすく、ライブラリやモジュールは使いやすいです。これこそがオブジェクト指向の利点です。

しかしその一方で、そのライブラリやモジュールを使いやすく書くのは難しいです。結構な熟練度を要します。

has-a で作るか is-a で作るか、継承にするかインターフェースにするか、継承関係をどのように構成するか、隠蔽する部分と外に見せる部分をどう分別するか、静的クラスで書くかクラスで書くか内部クラスで書くか、メソッド関数をどのようにオーバーライドしてどのように呼ぶか、機能分割をどのように行うか、共通化・汎用化を共通クラスで行うかジェネリクスやリフレクションで行うか、どのようなデザインパターンを使うか等々、オブジェクト指向には事前に思考を費やすべき設計考慮点がいくつもあります

慣れてしまえばある程度サクサクと進められますが、その水準に至るまでには相当な試行錯誤をする必要があり、この壁の高さに挫折する人は多いと考えられます。慣れたとしても、コードが成長するにつれて構造再設計・リファクタリングの必要性にせまられることがしばしばあります。

きちんと整理されたファイル・フォルダ構造は検索しやすく使いやすいものの、先々を見通してそのようにきれいに作るのは難しい、というのと同じです。

 · 
フォロー

オブジェクト指向=クラスを使ったプログラミングではありません。クラスはオブジェクト指向プログラミングを支援する言語仕様の一つです。クラスがないC言語でもオブジェクト指向プログラミングは可能です。GO言語、rustにもクラスはありませんがオブジェクト指向プログラミングは可能です。javascriptもクラスはありませんでしたが、オブジェクト指向プログラミング言語です。

このことから分かるように、オブジェクト指向というのは考え方であって実現方法ではないです。その実現方法は多岐に渡り、その考え方も時代と共に進化し変わってます。オブジェクト指向2つの呪いと言われているように、C++のいうオブジェクト指向実装とSmalltalkのいうオブジェクト指向実装と枝分かれした時代もありました。そしてオブジェクト指向の名付け親であるアラン·ケイはオブジェクト指向という命名は間違いであったとまで言っています。このことから本質はオブジェクト、クラスよりも重要なことがありそうです。クラスを使ったプログラミングは分かりやすいかもしれませんが、それはオブジェクト指向なのか?というと必ずしもそうで無いかもしれません。オブジェクト指向をサポートするプログラミング言語も最初のころは、構造化プログラミングを便利にする程度にしか使われてませんでした。最初はオブジェクト指向というのがあまり理解されていませんでした。クラスは使っているが構造化プログラミングから脱却できていない場合も多かったです。

構造化プログラミングも普及しはじめたのは70年代てすが、年月を重ねて完結したのは90年代と言われてます。そしてオブジェクト指向がこれを引き継いだといえます。

構造化プログラミングもオブジェクト指向プログラミングも奥が深く、その理解は難しいのです。

広告
 · 
フォロー

オブジェクト指向プログラミング言語を使っていても抽象化できているとは限りません。

main() しかないプログラムが書けないわけではありませんしね。

使う言語は関係ないんですよ。

抽象化して考える習慣ができているかどうかです。

プログラムなんて物理的な形もなく、手で触ることはできないんですから抽象化が全くできていなかったら作れません。

程度の差だけです。

抽象化しようとしない人には絶対にできないんですけどね。

0 コメント:

コメントを投稿