「4人のギャング」は間違っていたので、委任とは何かわからない

「4人組」は間違っていました。標準のRubyライブラリも誤りであり、Railsも誤りです。 しかし、誰もがこれを行うと何か間違っていますか?



はい



「Gangs of Four」「 Design Patterns 」という本は、基本的なOOPパターンを理解するための共通の語彙を提供します。 ソフトウェアを議論するときに同じ用語を使用するのに役立ちます。 残念ながら、混乱も引き起こします。



彼らは言う:「継承前の組成物」。 まあ、それは理にかなっています。 彼らは「委任を使う」と言います。 素晴らしい。 本には委任の単一の例はありませんが。



委任は、プログラムに柔軟性をもたらす可能性に起因する技術です。 通常、委任は構成を達成する方法であると言われています。 しかし、委任はあなたが考えるものではなく、4人組のギャングはあなたを迷わせました。 さらに悪いことに、委任へのほとんどすべての参照には、転送メッセージとオブジェクトのコラボレーションのみが含まれます。 これらは、委任ではなくメソッド呼び出しの例です。



プログラミングの先生は、プログラミングの基本的な概念をよく理解する必要があると言うでしょう。 そして、それらを正しく理解してください。



では、委任とは何ですか?



委任は簡単に理解できますが、この用語を他の何かの説明とともに常に見ているという事実を修正しましょう。



Henry Liebermanは、「プロトタイプオブジェクトを使用してオブジェクト指向システムに共有動作を実装する」という記事でこの用語を詳しく説明しました。 しかし、私はあなたにそれを送ることはしませんが、それを読むことは有用でしょう(またはそのオンライン版 )-私は代表団を説明するキーポイントをもたらします。 Liebermanは、GUI描画ツールのコンテキストでこの問題を議論しました。 基本的な考え方は次のとおりです。



ペンがレンダリングメッセージをペンプロトタイプに委任すると、「レンダリングメッセージの処理方法がわかりません。 可能であれば回答してください。変数xの値が何か、または何か他のことをする必要があるなど、さらに質問がある場合は、私に戻って質問する必要があります。 メッセージがさらに委任される場合、変数の値に関するすべての質問またはメッセージへの応答の要求は、最初にメッセージを委任したオブジェクトに送信されます。



つまり、オブジェクトにメッセージを送信すると、属性とメソッドを検索できるselfという概念があります。 このオブジェクトが権限を別のオブジェクトに委任すると、selfへのすべての参照は常に元のオブジェクトを指します。 常に。



その他の継承



クラスだけから継承することはできません。 プロトタイプベースの継承は、動作を共有できるようにオブジェクトを整理するもう1つの方法です。 1つのアプローチは抽象的な場所(クラス)で動作を確立し、もう1つのアプローチはインスタンス(オブジェクト)で動作します。



Selfは、Liebermanが話していることを実装するプログラミング言語です。 Selfには、スロットを含むオブジェクトがあります。 各スロットには、親スロット内のメソッドまたはプロトタイプオブジェクトへの参照を含めることができます。 オブジェクトがメッセージを受信し、それを理解できない場合、親スロットのオブジェクトにそれを委任できます。



これはプロトタイプではなくクラスの継承です。 これは、オブジェクトに追加の動作オプションを含むクラス(Rubyオブジェクトなど)がある場合の動作とほぼ同じですが、同一ではありません。



親スロットを持つオブジェクトのSelfでのプロビジョニングは、プロトタイプへのリンクを持つオブジェクトのJSでのプロビジョニングに似ています。 JSは最も人気のあるプロトタイプ言語であり、試してみるのがはるかに簡単です。 したがって、Selfは学習しませんが、すぐにJSを試します。 次のコードは、ブラウザコンソールで直接実行することもできます。



JSでは、プロトタイプ-Selfの親スロットに相当するものを割り当てることができます。



function Container(){}; Container.prototype = new Object(); Container.prototype.announce = function(){ alert("these are my things: " + this.things) }; function Bucket(things){this.things = things}; Bucket.prototype = new Container(); bucket = new Bucket("planes, trains, and automobiles") bucket.announce() // alerts "these are my things: planes, trains, and automobiles"
      
      







委任のコンテキストでは、バケットはメッセージをデリゲートに転送するクライアントです。 この例では、this.thingsの計算がクライアントオブジェクトのコンテキストで発生することがわかります。 アナウンスを呼び出すと、デリゲートオブジェクトで検出されます。 関数を評価するとき、これはクライアントを指します。



JSのプロトタイプオブジェクトに関数がある場合、オブジェクトにそのようなメソッドがあるかのように評価されます。 最初の例は、これ(JSではこれはself)が常にメッセージの元の受信者を指すことを示しています。



Rubyはどうですか?



まず、メッセージを転送する方法を理解しましょう。 転送とは、あるオブジェクトから別のオブジェクトにメッセージを送信することです。 転送可能な標準ライブラリはそのように命名されており、あるオブジェクトから別のオブジェクトにメッセージを転送できます。



さて、あまりよく知られていないデリゲートライブラリを取り上げましょう。これにより、あるオブジェクトから別のオブジェクトにメッセージを転送することもできます。



 require 'delegate' # assuming we have a Person class with a name method person = Person.new(:name => 'Jim') class Greeter < SimpleDelegator def hello "Hi! I'm #{name}." end end greeter = Greeter.new(person) greeter.hello #=> "Hi! I'm Jim."
      
      







グリーター内部で何が起こっているのですか? インスタンスが初期化されるとき、それは人への参照を含みます。 不明なメソッドが呼び出されると、ターゲットオブジェクト(つまり、person)に送信されます。 結局のところ、私たちはまだ委任ライブラリで作業しているので、メッセージの転送に役立ちます。 混乱した? そして、私も混乱していました。 どうやら他の世界と同じように。



転送とは、単にメッセージをオブジェクト(メソッド呼び出し)に転送することです。



それと委任の違いは、これらのライブラリを使用すると、JSのプロトタイプ継承の場合のように、最初のコンテキストで別のオブジェクトのメソッドを呼び出すだけでなく、追加のオブジェクトにメッセージを簡単に転送できることです。



Rubyのmethod_missing機能はSimpleDelegator内でこのトリックを行うため、通常は考えません。 そして、メソッドは目的のオブジェクトで魔法のように呼び出されると思います。 また、クライアントに目的のメソッドがない場合、Greeterはselfを参照しますが、メッセージは別のオブジェクトに転送され、そこで処理されます。



追加のメソッドでオブジェクトを拡張せずに動作を共有する必要がある場合は、method_missingやSimpleDelegatorが役立ちます。 単純なオプションの場合、これはうまく機能します。 しかし、このシステムはオブジェクトのクラスへの参照を壊します。



新しいタイプのグリーティングでクライアントオブジェクトクラスを参照する必要があるとします。 いつもの代わりに、「こんにちは! 私は尊敬される人物です、ジム。」 メソッドを書き換えるのではなく、単にsuperに依存して、通常のGreeterクラスで定義されているものを取得します。



 class ProperGreeter < Greeter def name "the esteemed " + self.class.name + ", " + super end end proper_greeter = ProperGreeter.new(person) proper_greeter.hello #=> "Hi! I'm the esteemed ProperGreeter, Jim."
      
      







それは私たちが望んでいたものではないことが少し判明しました。 尊敬されている人に会いたかった。



これは、2つのオブジェクトが実際にあるという事実と、OOPで自己が原因でどのように統合失調症が始まるかを示す簡単な例です。 各オブジェクトには、独自のアイデンティティと独自の自己理解があります。 (SimpleDelegatorが期待するように)selfの代わりに__getobj__へのリンクを変更することで状況を修正できますが、これはselfが必要なものを参照しない方法の例です。 2つのオブジェクトを操作する必要があり、プログラムの動作を考えるには、2つのオブジェクトが相互作用することを考える必要がありますが、実際には1つのオブジェクトの動作のみを変更します。



これは委任ではなく、2つのオブジェクトの相互作用です。 それ以外の場合あなたを説得する記事、書籍、図書館の束にもかかわらず。



まあ、それを何と呼ぼう



誰が気にします-結局のところ、誰もがそれをしますか?



ええ、「デザインパターン」のC ++の例です。 そして、C ++は委任する方法を知りません。 この議論は、用語の意味を再定義するのに十分ですか? 使用する言語にそのような機会がない場合、「委任」できるとは言わないでください。



コンセプトを修正します



アプリケーションを開発するには、その作業のロジックの概念だけでなく、アーキテクチャ開発のための多くのツールとアプローチを理解する必要があります。 プログラム設計パターンは、一般的な問題を解決する一般的な方法です。 それらがどのように機能し、いつ使用するかを理解することは、成功した開発者の重要な属性の1つです。



「Gangs of Four」「Design Patterns」という本は、基本的なOOPパターンを理解するための共通の語彙を提供します。 ソフトウェアを議論するときに同じ用語を使用するのに役立ちます。



Clean Rubyを書くために研究を始めたとき、Design Patternsに目を向けました。 「きっとこの本は、さまざまなテンプレートの使用についての正しい理解を深めるのに役立つでしょう」と私は思いました。 残念なことに、それには重大な間違いがあり、それは彼女の後、膨大な数の本、記事、図書館で繰り返されました。



「設計パターン」は、「継承前の構成」という考え方をうまく促進します。 多くの人がこのフレーズを好んでいるので、次にクラスの継承について議論するときに、頭に浮かぶでしょう。



「設計パターン」は、イノベーションではなく、用語の統合を称賛されることがよくあります。 問題を解決するさまざまな方法を理解し、議論するために使用する言語のガイドとして役立ちます。 彼女はお互いにもっと効果的にコミュニケーションできるように、一般に受け入れられているパターンに名前を付けました。 残念ながら、これらの賞賛は、あなたが代表団を整理しようとするとすぐに場違いになります。



私の本、Clean Rubyは、委任の理解に真剣に取り組み、プロジェクトを適切に編成し、プロジェクトをサポートし、疎結合にする可能性を探ります。 動作の分離を整理する方法を提供し、重要な概念の定義を明確にします。



All Articles