オブジェクト指向で渡すメッセージとは何ですか?


35

私は、主にC ++、C#、およびJavaでオブジェクト指向プログラミングを研究しています。カプセル化、継承、およびポリモーフィズムの理解(およびこのサイトで多くの質問を読むこと)で、それを十分に把握していると思いました。

ここにポップアップ表示されるように思われることの1つは、「メッセージパッシング」の概念です。どうやら、これは今日の主流言語でのオブジェクト指向プログラミングでは使用されていないが、Smalltalkでサポートされているものです。

私の質問は:

  • メッセージパッシングとは何ですか?(誰かが実用的な例を挙げることができますか?)
  • C ++、C#、またはJavaでこの「メッセージパッシング」をサポートしていますか?

4
私はしばらく前にこの質問に答えました:stackoverflow.com/a/3104741/10259
フランクシェラー

1
ウィキペディアの記事を読みましたか?
ヤンニス

4
私の謙虚な意見では、Objective-Cは主流言語としての資格を得るでしょう。少なくともC#と同じくらい。
mouviciel

私はそれに同意します。私の経験から「主流」言語を述べていました
トム

メンバー関数呼び出しは、メッセージを渡す実装の1つです。渡されたメッセージは関数名で識別され、パラメーターからの情報が含まれます。遅延バインディングにより、受信クラスは同じメッセージを他のクラスとは異なる方法で処理できます。Simulaの作成者が意図したものではなく、多くの人がメッセージパッシングを呼び出して、メッセージパッシングを行うことがSimulaを異なる重要なものであると(正当な理由で)呼び出すことに反対しますが、メンバー関数呼び出しは基本的に同じことを行いますジョブ。
Steve314

回答:


60

メッセージパッシングとは何ですか?(誰かが実用的な例を挙げることができますか?)

メッセージの受け渡しとは、単に(非常に抽象的なレベルで)プログラム実行の基本的なメカニズムが、お互いにメッセージを送信するオブジェクトであることを意味しています。重要な点は、これらのメッセージの名前と構造がソースコードで事前に固定されている必要はなく、それ自体が追加情報になる可能性があることです。これは、アランケイが当初「オブジェクト指向プログラミング」として想定していたことの重要な部分です。

C ++、C#、またはJavaでこの「メッセージパッシング」をサポートしていますか?

これらの言語は、メソッド呼び出しを通過するメッセージの限定バージョンを実装します。送信できるメッセージのセットはクラスで宣言されたメソッドに限定されるため、制限されます。このアプローチの利点は、非常に効率的に実装でき、非常に詳細な静的コード分析が可能になることです(コード補完など、あらゆる種類の有益な利点が得られます)。

逆に、「本物の」メッセージの受け渡しを実装する言語には、メッセージハンドラを実装する便利な方法としてメソッド定義もよくありますが、オブジェクトが任意の名前(修正されていない)で「メソッド呼び出し」コンパイル時)。

この概念の力を示すGroovy

def xml = new MarkupBuilder(writer)
xml.records() {
  car(name:'HSV Maloo', make:'Holden', year:2006) {
    country('Australia')
    record(type:'speed', 'Production Pickup Truck with speed of 271kph')
  }
}

このXMLを生成します:

<records>
  <car name='HSV Maloo' make='Holden' year='2006'>
    <country>Australia</country>
    <record type='speed'>Production Pickup Truck with speed of 271kph</record>
  </car>
</records>

なおrecordscarcountryおよびrecord構文的メソッド呼び出しですが、中に定義されたその名前のない方法はありませんMarkupBuilder。代わりに、すべてのメッセージを受け入れ、メッセージ名をXML要素の名前、パラメーターを属性、クロージャーを子要素として解釈するキャッチオールメッセージハンドラーがあります。


ポイントの答えにまっすぐに+1。コード例で受け入れられました。ご協力ありがとうございます:)
トム

だから、それが単にシンプルで実現することができませんでしたsendMessage(property_name, Array of arguments)し、getMessage(property_name, Array of arguments)静的言語で?
パセリエ

1
@Pacerier:確かに、それは両方のアプローチの短所を組み合わせています-型の安全性を失い、どこでもコードを汚染する "sendMessage"があるので、エレガントな構文が得られません。
マイケルボルグワード

Groovyの例では、メッセージハンドラーはメソッド呼び出しではなくメッセージを受信して​​いると言う方が正しいでしょうか?最初にフレーズ「メソッド呼び出し」を引用符で囲みますが、最後の文では、「メッセージ」ではなく「すべてのメソッドを受け入れます」と言います。
アダムゼルナー

@AdamZerner:あなたは正しい、私はそれを修正しました。
マイケルボルグワート

28

メッセージの受け渡しは、あるオブジェクトが別のオブジェクト(または潜在的にそれ自体)に何かをさせるためのオブジェクト指向コードの必要性を処理する別の方法です。

C ++アプローチから派生した最新のほとんどの言語では、メソッド呼び出しでそれを行います。この場合、呼び出されたオブジェクトは(そのクラス定義を介して)受け入れるメソッド呼び出しの大きなリストを配置し、呼び出し元オブジェクトのコーダーは単に呼び出しを記述します。

public void doSomething ( String input )
...
other_object.dosomething ( local )

静的に型付けされた言語の場合、コンパイラは呼び出されているものの型をチェックし、メソッドが宣言されていることを確認できます。動的に型付けされた言語の場合、実行時に実行されます。

しかし、本質的に起こるのは、変数の束が特定のコードブロックに送信されることです。

メッセージの受け渡し

メソッドの代わりにメッセージパッシング言語(Objective Cなど)には受信者がいますが、それらを定義して呼び出す方法はほぼ同じです。違いは処理方法です。

メッセージが渡された言語では、コンパイラ、呼び出したレシーバーが存在することを確認する場合がありますが、最悪の場合、そこにあるかどうかわからないという警告がポップアップ表示されます。これは、実行時に、受信側オブジェクトのコードブロックが呼び出され、変数のバンドルと呼び出したい受信側の署名の両方が渡されるためです。次に、そのコードブロックは受信者を探して呼び出します。ただし、レシーバーが存在しない場合、コードは単にデフォルト値を返します。

その結果、C ++ / Java-> Objective Cから移行するときに見られる奇妙な点の1つは、コンパイル時の型で宣言されておらず、さらには実行時のタイプ...および呼び出しによって例外がスローされることはなく、実際には結果が返されること。

このアプローチの利点は、サブクラスの階層を平坦化し、インターフェイス/多重継承/ダックタイプのほとんどのニーズを回避できることです。また、オブジェクトは、受信者がいない何かをするように要求されたときのデフォルトの動作を定義することを許可します(一般的に「そうしない場合、この他のオブジェクトにリクエストを転送します」)。また、特にJavaなどの静的に型指定された言語でのコールバック(UI要素や時限イベントなど)へのリンクを簡素化できます(したがって、ボタンは、内部クラスで "actionPerformed"メソッドを呼び出すのではなく、レシーバー "runTest" 「RunTestButtonListener」が呼び出しを行います)。

ただし、開発者が追加のチェックを行う必要がありますが、開発者は、適切なタイプの適切なオブジェクトで適切なパラメータを適切な順序で渡すことができると考えているため、コンパイラが警告すると、実行時に完全に実行されます(デフォルトの応答を返すだけです)。おそらく、追加のルックアップとパラメーターの受け渡しによるパフォーマンスの低下もあります。

最近では、動的に型付けされた言語は、OOを通過したメッセージの多くの利点を、より少ない問題で提供できます。


1
私はこの答えが好きです-違いとその意味を説明しています。
HappyCat

@Gavin、それはPHPとJavascriptの動的メソッドハンドラまったく同じですか?
パセリエ

11

メッセージパッシングアーキテクチャは、各コンポーネントが他のコンポーネントから独立している単純なシステムであり、コンポーネント間でデータを渡すための共通のメカニズムを備えています。メソッド呼び出しはメッセージパッシングの一形態と見なすことができますが、そうすることは実用的ではありません。問題を混乱させます。これは、明確に定義されたメソッドを持つクラスと、それらのメソッドを呼び出すコードがある場合、コード全体とオブジェクトを一緒にコンパイルする必要があるためです。それがどのように近いかを見ることができます(メッセージが渡され、コンパイラが正確さを強制しているが、分離されたシステムの柔軟性の多くを失います)。

メッセージ受け渡しアーキテクチャでは、多くの場合、実行時にオブジェクトを追加できます。多くの場合、メッセージを1つ以上のオブジェクトにリダイレクトできます。そのため、システムにロードされたすべてのオブジェクトに「データxが更新されました」というメッセージをブロードキャストするコードを作成できます。各コードは、その情報で好きなアクションを実行できます。

奇妙な例はウェブです。HTTPはメッセージパッシングシステムです。コマンド動詞と「データパケット」をサーバープロセスに渡します。(例:GET http:\ myserver \ url)ブラウザもWebサーバーも、送信するデータや送信先については何も気にしません。サーバーはそれを別の「パケット」のデータをパッケージ化してあなたに送り返すコードに渡します。このシステムのコンポーネントは、他の機能やその機能について何も知りません。メッセージ通信に使用されるプロトコルを知っているだけです。


@gbjbannb、いくつかの擬似コードの説明が必要です
。...-Pacerier
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.