OOプログラミング、主にC++、C#、およびJavaでのプログラミングを研究しています。カプセル化、継承、およびポリモーフィズムについて理解しているので、それをよく理解していると思いました。
OOを説明するときによく参照される概念の1つは「メッセージパッシング」です。明らかに、これはOO今日の主流言語でのプログラミングでは使用されませんが、 Smalltalkでサポートされています。
私の質問は:
メッセージパッシングとは(誰かが実際的な例を挙げられますか?)
メッセージパッシングとは、(非常に抽象的なレベルで)プログラム実行の基本的なメカニズムが、互いにメッセージを送信するオブジェクトであることを意味します。重要な点は、これらのメッセージの名前と構造は、必ずしもソースコードで事前に固定されている必要はなく、それ自体が追加情報になる可能性があることです。これは、Alan Kayが当初「オブジェクト指向プログラミング」として構想していた重要な部分です。
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>
records
、car
、country
およびrecord
は構文的にメソッド呼び出しですが、MarkupBuilder
で定義されたその名前のメソッドはないことに注意してください。代わりに、すべてのメッセージを受け入れ、メッセージ名をXML要素の名前として解釈し、パラメーターを属性として、クロージャーを子要素として解釈するキャッチオールメッセージハンドラーがあります。
メッセージの受け渡しは、あるオブジェクトが別のオブジェクト(または潜在的にそれ自体)に何かを実行させるためのOOコードの必要性を処理する別の方法です。
C++アプローチから派生した最近のほとんどの言語では、これをメソッド呼び出しで行います。この場合、呼び出されたオブジェクトは(そのクラス定義を介して)受け入れるメソッド呼び出しの大きなリストを配置し、呼び出し側オブジェクトのコーダーは呼び出しを記述します。
public void doSomething ( String input )
...
other_object.dosomething ( local )
静的に型付けされた言語の場合、コンパイラーは呼び出されるもののタイプをチェックし、メソッドが宣言されていることを確認できます。動的に型付けされた言語の場合は、実行時に実行されます。
しかし、本質的には、変数のバンドルが特定のコードブロックに送信されるということが起こります。
メッセージの受け渡し
メソッドの代わりにメッセージパッシング言語(Objective Cなど)にはレシーバーがありますが、それらを定義して呼び出す方法はおおむね同じです-違いはその処理方法です。
メッセージが渡された言語では、コンパイラーが呼び出したレシーバーが存在することを確認しますが、最悪の場合、存在しないことを警告するポップアップが表示されますそこにあることを確認してください。これは、実行時に発生するのは、変数のバンドルと呼び出すレシーバーのシグネチャの両方を渡して、受信オブジェクトのコードブロックが呼び出されるためです。次に、そのコードブロックはレシーバーを探して呼び出します。ただし、レシーバーが存在しない場合、コードはデフォルト値を返すだけです。
その結果、C++/Java-> Objective Cから移動するときに発見された奇妙な点の1つは、コンパイル時の型で宣言されておらず、存在していなかったオブジェクトで「メソッドを呼び出す」ことができることを理解しています。実行時のタイプ...および呼び出しによって例外がスローされることはなく、実際には結果が返されること。
このアプローチの利点は、サブクラスの階層を平坦化し、インターフェイス/複数の継承/アヒルのタイプの必要性のほとんどを回避できることです。また、オブジェクトがレシーバーを持たない何かを実行するように要求されたときに、オブジェクトがデフォルトの動作を定義できるようにします(通常、「実行しない場合は、この他のオブジェクトに要求を転送します」)。また、特にJavaなどの静的に型付けされた言語では、コールバックへのリンク(たとえば、UI要素や時限イベントの場合)へのリンクを簡略化できます(そのため、ボタンではなく、レシーバーに「runTest」を呼び出すことができます)呼び出しを行う内部クラス「RunTestButtonListener」の「actionPerformed」メソッド)。
ただし、開発者が追加のチェックを行う必要があるという犠牲を払って、コンパイラが行わない可能性があるため、彼らが行っていると考える呼び出しが、適切な型の適切なオブジェクトと適切な順序で渡されることを犠牲にすると思われます。警告し、実行時に完全に実行されます(デフォルトの応答を返すだけです)。間違いなく、追加のルックアップとパラメーターの受け渡しによるパフォーマンスへの影響もあります。
最近、動的に型付けされた言語は、渡されるメッセージの多くの利点を提供できますOOより少ない問題で。
メッセージパッシングアーキテクチャは、各コンポーネントが他のコンポーネントから独立している単純なシステムであり、それらの間でデータを受け渡すための共通のメカニズムを備えています。メソッド呼び出しをメッセージパッシングの1つの形式と見なすことができますが、そうすることは現実的ではありません。問題を混乱させます。これは、明確に定義されたメソッドを持つクラスと、それらのメソッドを呼び出すコードがある場合、全体を一緒にコンパイルして、コードとオブジェクトを結合する必要があるためです。メッセージが渡されていて、コンパイラが正確さを強制しているが、分離システムの柔軟性の多くを失っているので、どのように近いかがわかります。
メッセージパッシングアーキテクチャでは、多くの場合、実行時にオブジェクトを追加できますが、多くの場合、メッセージを1つ以上のオブジェクトにリダイレクトできます。そのため、システムにロードされたすべてのオブジェクトに「データxが更新されました」メッセージをブロードキャストするコードを使用でき、それらの各オブジェクトは、その情報を使用して好きなアクションを実行できます。
奇妙な例はウェブです。 HTTPはメッセージパッシングシステムです。コマンド動詞と「データパケット」をサーバープロセスに渡します。 (例:GET http:\ myserver\url)ブラウザーもWebサーバーも、送信するデータや送信先を気にしません。サーバーはそれをコードに渡し、データの別の「パケット」をパッケージ化して、ユーザーに送り返します。このシステムのコンポーネントは、他の動作やその動作について何も認識せず、メッセージ通信に使用されるプロトコルを知っているだけです。