C# の人はオブジェクト指向プログラミングを習得できないと主張されるのはなぜですか?(対クラス指向)

StackOverflow https://stackoverflow.com/questions/52092

  •  09-06-2019
  •  | 
  •  

質問

昨夜、これが私の注意を引きました。

最新について ALT.NET ポッドキャスト Scott Bellware は、Ruby とは対照的に、C#、Java などの言語がどのように機能するかについて説明します。真のオブジェクト指向ではなく、「クラス指向」という言葉を選択しています。彼らはこの違いについて、詳細には触れず、メリットとデメリットについてもあまり議論せず、非常に曖昧な言葉で語っています。

ここでの実際の違いは何でしょうか?また、それはどの程度重要ですか?では、他の言語が「オブジェクト指向」であるのでしょうか?とても面白そうですが、何か足りないものがあるかどうかを知るためだけに Ruby を学ぶ必要はありません。

アップデート:以下の回答のいくつかを読んだ後、人々は一般的にダックタイピングへの言及であることに同意しているようです。しかし、私がまだ理解しているかどうか確信が持てないのは、これが最終的にはそれほど大きな変化をもたらすという主張です。特に、すでに疎結合で適切な TDD を実行している場合は特にそうです。誰かが、Ruby ではできて C# ではできない素晴らしいこと、そしてこの異なる oop アプローチを例示する例を示してくれませんか?

役に立ちましたか?

解決

ここでのダックタイピングのコメントは、Ruby と Python がより優れているという事実に起因しています。 動的 C#よりも。OO Nature とは実際には何の関係もありません。

Bellware がこれで言いたかったのは、Ruby ではすべてがオブジェクトであるということです。授業でも。クラス定義はオブジェクトのインスタンスです。そのため、実行時に動作を追加/変更/削除できます。

もう 1 つの良い例は、NULL もオブジェクトであることです。Ruby では、文字通りすべてがオブジェクトです。このように深い OO が全体に組み込まれているため、method_missing などの楽しいメタプログラミング手法が可能になります。

他のヒント

オブジェクト指向言語では、クラスではなくオブジェクトを定義することによってオブジェクトが定義されますが、クラスは特定の抽象化の特定の型にはまった定義に役立つテンプレートを提供できます。たとえば C# などのクラス指向言語では、オブジェクトはクラスによって定義する必要があり、これらのテンプレートは通常、缶詰およびパッケージ化され、実行前に不変になります。オブジェクトは実行前に定義されなければならず、オブジェクトの定義は不変であるというこの任意の制約は、オブジェクト指向の概念ではありません。それはクラス指向です。

IMO、それは本当に「オブジェクト指向」を定義しすぎていますが、彼らが言及しているのは、C#、C++、Java などとは異なり、Ruby は 定義する クラス -- 実際にオブジェクトを直接操作することしかできません。逆に、たとえば C# では、次のように定義します。 クラス そうすればあなたはそうしなければなりません インスタンス化する new キーワードを使用してオブジェクトに取り込みます。重要な点は、次のことです。 宣言する C# のクラスを指定するか、それを説明します。さらに、Rubyでは、 すべて -- たとえば、偶数は -- オブジェクトです。対照的に、C# にはオブジェクト型と値型の概念がまだ残っています。実際、これは C# や他の同様の言語、つまりオブジェクトについて彼らが指摘している点を示していると思います。 タイプ そして価値観 タイプ 暗示する タイプ システム、つまりシステム全体があることを意味します。 記述 単にオブジェクトを操作するのではなく、型を使用します。

概念的には、OOだと思います デザイン は、最近のソフトウェア システムの複雑さに対処するために使用できる抽象化を提供します。言語は OO 設計を実装するために使用されるツールです。あるものは他のものよりも自然にします。私は、より一般的でより広範な定義から言えば、C# やその他の言語は依然として オブジェクト指向 言語。

OOP には 3 つの柱があります

  1. カプセル化
  2. 継承
  3. ポリモーフィズム

言語がこれら 3 つのことを実行できる場合、それは OOP 言語です。

私は、言語 X が言語 A よりも OOP に優れているという議論が永遠に続くと確信しています。

OO は次のように定義されることもあります メッセージ指向. 。その考え方は、メソッド呼び出し (またはプロパティ アクセス) は実際には別のオブジェクトに送信されるメッセージであるということです。受信オブジェクトがメッセージを処理する方法は完全にカプセル化されています。多くの場合、メッセージは実行されるメソッドに対応しますが、それは実装の詳細にすぎません。たとえば、メッセージ内のメソッド名に関係なく実行されるキャッチオール ハンドラーを作成できます。

C# のような静的 OO には、この種のカプセル化がありません。マッサージ もっている 既存のメソッドまたはプロパティに対応させる必要があります。そうでない場合、コンパイラからエラーが発生します。ただし、Smalltalk、Ruby、Python などの動的言語は、「メッセージベース」の OO をサポートしています。

したがって、この意味では、C# やその他の静的に型付けされた OO 言語は、「真の」カプセル化が欠けているため、真の OO ではありません。

アップデート:それは新しい波です..これは、私たちが今までやってきたことはすべて時代遅れであることを示唆しています。ポッドキャストや本でかなり話題になっているようです。もしかしたら、これがあなたが聞いたことかもしれません。

これまで私たちは静的クラスに注目してきましたが、 解き放たれた オブジェクト指向開発の力。私たちは「クラスベースの開発者」をやっています。クラスは、オブジェクトを作成するための固定/静的テンプレートです。クラスのすべてのオブジェクトは平等に作成されます。

例えば私が何について話しているのかを説明するために...私がちょうど見る特権を得た PragProg スクリーンキャストから Ruby コード スニペットを拝借させてください。「プロトタイプベースの開発」では、オブジェクトとクラスの境界があいまいになります。違いはありません。

animal = Object.new                  # create a new instance of base Object

def animal.number_of_feet=(feet)     # adding new methods to an Object instance. What?
  @number_of_feet = feet
end
def animal.number_of_feet
  @number_of_feet
end

cat = animal.clone          #inherits 'number_of_feet' behavior from animal
cat.number_of_feet = 4

felix = cat.clone           #inherits state of '4' and behavior from cat
puts felix.number_of_feet   # outputs 4

このアイデアは、従来のクラスベースの継承よりも状態と動作を継承する強力な方法です。これにより、特定の「特別な」シナリオ (私はまだ理解していません) において、より柔軟な制御が可能になります。これにより、ミックスイン (クラス継承なしの動作の再使用) のようなことが可能になります。

問題に対する私たちの考え方の基本的な考え方に挑戦することにより、「真の OOP」はある意味「マトリックス」に似ています...なんてことをループし続けます。このように..ここで、Container の基本クラスは、生成される乱数が 0.5 のどちら側にあるかに基づいて、配列またはハッシュのいずれかになります。

class Container < (rand < 0.5 ? Array : Hash)
end

Ruby、JavaScript、そして新しい旅団がこれを先駆けているようです。これについてはまだ未定です...この新しい現象を読んで理解しようとしています。力がありそうです..強すぎる..役に立つ?もう少し目を開いてほしい。興味深い時代..これら。

あなたの質問のきっかけとなったポッドキャストの最初の 6 ~ 7 分しか聞いていません。C# は純粋なオブジェクト指向言語ではない、ということが彼らの意図であるとすれば、それは実際には正しいです。C# ではすべてがオブジェクトではありません (ボックス化すると同じ値を含むオブジェクトが作成されますが、少なくともプリミティブはオブジェクトではありません)。Ruby ではすべてがオブジェクトです。Daren と Ben は「ダックタイピング」についての議論で基本をすべて網羅しているようですので、繰り返しません。

この違い (すべてがオブジェクトであるか、すべてがオブジェクトではないのか) が重要であるかどうかは、C# と比較できるほど Ruby について十分な知識がないため、すぐに答えることができない質問です。Smalltalk を知っているここにいる人たち (私は知りませんが、知っていればよかったのですが) は、30 年前に Ruby が最初の純粋な OO 言語であった頃から、おそらく Ruby の動きを面白がって見てきたでしょう。

おそらく、彼らはダックタイピングとクラス階層の違いをほのめかしているのでしょうか?

もしそれがアヒルのように歩き、アヒルのように鳴くなら、アヒルのふりをして蹴ってください。

C#、Javaなどでコンパイラは次のことについて大騒ぎします。そのオブジェクトに対してこの操作を実行することは許可されていますか?

オブジェクト指向 vs.したがって、クラス指向とは次のことを意味します。言語はオブジェクトやクラスを考慮しますか?

例えば:Python では、反復可能なオブジェクトを実装するには、メソッドを指定するだけで済みます。 __iter__() という名前のメソッドを持つオブジェクトを返します。 next(). 。必要なのはこれだけです。インターフェイスの実装はありません (そのようなものはありません)。サブクラス化はありません。アヒル/反復子のように話しているだけです。

編集: この投稿はすべて書き直している間に賛成票を投じられました。申し訳ありませんが、二度とそのようなことはしません。オリジナルのコンテンツには、できるだけ多くの言語を学び、言語医師が言語について何を考えているか、何を言っているかを心配しないようにというアドバイスが含まれていました。

それはまさに抽象的なポッドキャストでした。
しかし、彼らが何を目指しているのかはわかります。彼らはルビーの輝きにただ目をくらませているだけなのです。Ruby を使用すると、C ベースや Java のプログラマーが思いつかないようなことを実行でき、それらを組み合わせることで、夢にも思わない可能性を実現できます。組み込みの String クラスに新しいメソッドを追加したり、他の人が実行できるように名前のないコード ブロックを渡したり、ミックスイン...従来の人々は、オブジェクトがクラス テンプレートから大きく外れて変更されることに慣れていません。そこには確かに全く新しい世界が広がっています。

C# の人たちは OO が十分ではありません...気にしないでください。言葉に詰まったときに話す内容だと思ってください。Ruby はほとんどの人に同じことをします。
この 10 年間に人々に学ぶべき言語を 1 つ勧めるなら...それはルビーでしょう。よかったです。Python だと主張する人もいるかもしれませんが。でもそれは私の意見に似ています..男!:D

これは特にダックタイピングに関するものではないと思います。たとえば、C# はすでに限定的なダックタイピングをサポートしています。たとえば、次のような場合に foreach を使用できます。 どれでも MoveNext と Current を実装するクラス。

ダックタイピングの概念は Java や C# などの静的型付け言語と互換性があり、基本的にはリフレクションの拡張です。

これは実際には、静的型付けと動的型付けのケースです。そんなことがあるくらい、どちらもちゃんと○○です。学界の外では、議論する価値はまったくありません。

ゴミコードはどちらでも記述できます。優れたコードはどちらでも記述できます。あるモデルでできて他のモデルではできない機能はまったくありません。

本当の違いは、実行されるコーディングの性質にあります。静的型は自由度を減らしますが、誰もが何を扱っているかを知っているという利点があります。インスタンスをその場で変更できるのは非常に強力ですが、その代償として、何をやっているのかがわかりにくくなります。

たとえば、Java または C# の場合、インテリセンスは簡単です。IDE は可能性のドロップ リストを迅速に作成できます。Javascript や Ruby の場合、これは非常に困難になります。

他の人がコーディングする API を作成するなど、特定のことに関しては、静的型付けには大きな利点があります。たとえば、プロトタイプを迅速に作成する場合など、その利点はダイナミックなものになります。

スキル ツールボックスで両方を理解することは価値がありますが、すでに使用している方を実際に深く理解することほど重要なことはありません。

オブジェクト指向は概念です。このコンセプトは特定のアイデアに基づいています。これらのアイデア (実際には、時間の経過とともに進化し、最初の 1 時間から存在するものではない原則) の技術的な名前はすでに上に示したので、繰り返すつもりはありません。私はこれをできる限り単純かつ非専門的に説明しています。

OO プログラミングの考え方は、オブジェクトが存在するということです。オブジェクトは小さな独立した実体です。これらのエンティティには情報が埋め込まれている場合もあれば、埋め込まれていない場合もあります。そのような情報を持っている場合、そのエンティティ自体のみがその情報にアクセスしたり変更したりできます。エンティティは、相互にメッセージを送信することによって相互に通信します。これを人間に例えてみましょう。人間は独立した存在であり、脳内に内部データが保存されており、通信することで相互に作用します(例:お互いに話しています)。他人の脳から得た知識が必要な場合、直接アクセスすることはできません。質問する必要があります。そうすれば、彼はそれに答えて、あなたが知りたかったことを教えてくれるかもしれません。

基本的にはそれだけです。これが、OO プログラミングの背後にある本当の考え方です。これらのエンティティを作成し、エンティティ間の通信を定義し、相互作用してアプリケーションを形成します。この概念はどの言語にも束縛されません。これは単なる概念であり、C#、Java、または Ruby でコードを作成する場合、それは重要ではありません。追加の作業を行うことで、この概念は関数型言語であるにもかかわらず純粋な C で実行することもでき、概念に必要なものはすべて提供されます。

現在、さまざまな言語がこの OO プログラミングの概念を採用していますが、当然のことながら、これらの概念は常に同じであるわけではありません。たとえば、他の言語で禁止されている内容を許可する言語もあります。ここで関係する概念の 1 つはクラスの概念です。言語によってはクラスがあるものもあれば、クラスがないものもあります。クラスは、オブジェクトがどのように見えるかの設計図です。オブジェクトの内部データ ストレージを定義し、オブジェクトが理解できるメッセージと、継承があるかどうかを定義します (つまり、 必須ではありません オブジェクト指向プログラミングの場合!)、クラスは、このクラスが他のどのクラス (多重継承が許可されている場合は複数のクラス) から継承するか (選択的継承が存在する場合はどのプロパティも) も定義します。このようなブルー​​プリントを作成したら、このブループリントに従って構築されたオブジェクトを無制限に生成できるようになります。

ただし、クラスを持たない OO 言語もあります。では、オブジェクトはどのように構築されるのでしょうか?まあ、通常は動的に。例えば。新しい空のオブジェクトを作成し、それにインスタンス変数やメソッド (メッセージ) などの内部構造を動的に追加できます。または、既存のオブジェクトをそのすべてのプロパティとともに複製して、それを変更することもできます。あるいは、2 つのオブジェクトを新しいオブジェクトにマージすることもできます。クラスベースの言語とは異なり、これらの言語は非常に動的であり、コードの作成時に開発者ですら思いつかなかった方法で、実行時にオブジェクトを動的に生成できます。

通常、このダイナミックには次のような価格がかかります。言語が動的であればあるほど、メモリ (RAM) オブジェクトの浪費が多くなり、プログラム フローも非常に動的になるため、すべてが遅くなり、コードやデータ フローを予測する機会がない場合、コンパイラーが効果的なコードを生成するのは困難になります。JIT コンパイラは、プログラム フローを把握すれば、実行時にその一部を最適化できますが、これらの言語は非常に動的であるため、プログラム フローはいつでも変更される可能性があり、JIT はすべてのコンパイル結果を破棄して同じコードを再コンパイルする必要があります。何度も何度も。

ただし、これは実装の小さな詳細であり、基本的な OO 原則とは何の関係もありません。オブジェクトが動的である必要がある、または実行時に変更可能である必要があるとはどこにも述べられていません。ウィキペディアには次のようによく書かれています。

プログラミング手法には、情報の隠れ、データの抽象化、カプセル化、モジュール性、多型、継承などの機能が含まれる場合があります。

http://en.wikipedia.org/wiki/オブジェクト指向プログラミング

彼らは 5月 または彼ら ではないかもしれない. 。これはすべて必須ではありません。必須なのは、オブジェクトの存在と、オブジェクトが相互に対話する方法を持っていることだけです (そうしないと、オブジェクトが相互に対話できない場合、オブジェクトはまったく役に立たなくなります)。

あなたはこう尋ねました:「誰か、Ruby ではできて C# ではできない素晴らしいこと、そしてこの異なる oop アプローチの例を示してくれませんか?」

良い例の 1 つは、レールに組み込まれた ORM であるアクティブ レコードです。モデル クラスは、データベース スキーマに基づいて実行時に動的に構築されます。

これはおそらく、OOP をサポートする C# と Java ではなく、C# と Java で他の人がやっているのをこれらの人々が見ているということです。ほとんどの言語は、さまざまなプログラミング パラダイムで使用できます。たとえば、C# とスキームで手続き型コードを記述したり、Java で関数型スタイルのプログラミングを実行したりできます。それよりも、何をしようとしているのか、言語が何をサポートしているのかが重要です。

これに挑戦してみます。

Python と Ruby はアヒル型です。これらの言語で保守可能なコードを生成するには、ほとんどの場合、テスト駆動開発を使用する必要があります。そのため、開発者にとって、巨大なサポート フレームワークを作成せずにコードに依存関係を簡単に挿入できることが非常に重要です。

依存関係の注入が成功するかどうかは、非常に優れたオブジェクト モデルがあるかどうかにかかっています。この 2 つはある意味、同じコインの裏表のようなものです。OOP の使用方法を本当に理解している場合は、依存関係を簡単に注入できる設計をデフォルトで作成する必要があります。

動的型付け言語では依存関係の注入が簡単であるため、Ruby/Python 開発者は、自分たちの言語が他の静的型付け言語よりもオブジェクト指向の教訓をはるかによく理解していると感じています。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top