DoSomethingToThing(Thing n) と Thing.DoSomething()
-
09-06-2019 - |
質問
どのアプローチがより適切であるかを決定する要因は何ですか?
解決
どちらもそれぞれの立場があると思います。
単純に使用すべきではありません DoSomethingToThing(Thing n)
「関数型プログラミングは良い」と思っているからです。同様に、単に使用すべきではありません Thing.DoSomething()
なぜなら「オブジェクト指向プログラミングは優れている」からです。
それは何を伝えようとしているのかということになると思います。コードを一連の命令として考えるのをやめて、物語の段落や文のように考え始めてください。目の前のタスクの観点からどの部分が最も重要であるかを考えてください。
たとえば、強調したい「文」の部分がオブジェクトである場合は、OO スタイルを使用する必要があります。
例:
fileHandle.close();
ファイル ハンドルをやり取りするとき、主に考えているのは、ファイル ハンドルが表すファイルを追跡することです。
反例:
string x = "Hello World";
submitHttpRequest( x );
この場合、HTTP リクエストの送信は、本文である文字列よりもはるかに重要であるため、 submitHttpRequst(x)
より好ましい x.submitViaHttp()
言うまでもなく、これらは相互に排他的ではありません。おそらく実際に持っているでしょう
networkConnection.submitHttpRequest(x)
両方を混ぜ合わせます。重要なのは、どの部分を強調し、コードを将来読む人に何を伝えるかを考えることです。
他のヒント
オブジェクト指向になるには、尋ねるのではなく教えてください: http://www.pragmaticprogrammer.com/articles/tell-dont-ask.
したがって、DoSomethingToThing(Thing n) ではなく Thing.DoSomething() です。
モノの内部状態を扱う場合は、Thing.DoSomething() の方が合理的です。これは、たとえ Thing の内部表現やその動作方法を変更したとしても、それと通信するコードを変更する必要がないためです。Things のコレクションを扱っている場合、またはいくつかのユーティリティ メソッドを作成している場合は、手続き型スタイルの DoSomethingToThing() の方が理にかなっているか、より簡単かもしれません。ただし、通常はそのコレクションを表すオブジェクトのメソッドとして表すことができます。例えば
GetTotalPriceofThings();
対
Cart.getTotal();
それは実際、コードがどの程度オブジェクト指向であるかによって異なります。
- 何かをする Thing が文の主語である場合に適切です。
- DoSomethingToThing(Thing n) Thing が文の目的語である場合に適切です。
- 物A.物Bに何かをする(物B m) 私が考えることのできるすべての言語で、関数は 1 つのクラスに属し、相互に所有されていないため、これは避けられない組み合わせです。しかし、主語と目的語を持つことができるので、これは理にかなっています。
能動態は受動態よりも単純なので、文の主語が「コンピューター」だけではないことを確認してください。これは、フォーム 1 とフォーム 3 を頻繁に使用し、フォーム 2 をほとんど使用しないことを意味します。
明確にするために:
// Form 1: "File handle, close."
fileHandle.close();
// Form 2: "(Computer,) close the file handle."
close(fileHandle);
// Form 3: "File handle, write the contents of another file handle."
fileHandle.writeContentsOf(anotherFileHandle);
私も Orion さんの意見に同意しますが、決定プロセスを言い換えます。
名詞と動詞、目的語とアクションがあります。
- このタイプの多くのオブジェクトがこのアクションを使用する場合は、アクションをオブジェクトの一部にするようにしてください。
- それ以外の場合は、アクションを個別に、ただし関連するアクションと一緒にグループ化してみてください。
ファイル / 文字列の例が気に入っています。「SendAsHTTPReply」などの文字列操作は数多くありますが、これらは平均的な文字列では発生しませんが、特定の設定では頻繁に発生します。ただし、基本的には常にファイルを閉じることになるため (できれば)、クラス インターフェイスに Close アクションを置くのは完全に理にかなっています。
これをエンターテイメント システムの一部を購入するという考え方もできます。テレビは常に一緒に使用するため、テレビのリモコンを同梱するのが合理的です。しかし、多くの顧客はこれを決して使用しないため、特定のビデオデッキ用の電源ケーブルをテレビに同梱するのは奇妙です。重要なアイデアは このアクションがこのオブジェクトに対してどのくらいの頻度で使用されるか?
ここでは十分な情報がありません。それは、あなたの言語が「Thing.something」または同等の構造をサポートしているかどうかによって異なります。それは OO 言語です)。そうであれば、それが OO パラダイムであるため、その方がはるかに適切です (メンバーは、そのメンバーが動作するオブジェクトに関連付けられる必要があります)。もちろん、手続き型スタイルでは、DoSomethingtoThing() が唯一の選択肢です...または ThingDoSomething()
DoSomethingToThing(Thing n) は機能的なアプローチであるのに対し、Thing.DoSomething() はオブジェクト指向のアプローチです。
それがオブジェクト指向か手続き型プログラミングの選択です:)
よく文書化された OO の利点は Thing.DoSomething() にも当てはまると思います。
考慮すべき要素がいくつかあります。
- 変更または拡張できますか
Thing
クラス。そうでない場合は、前者を使用してください - できる
Thing
インスタンス化される。そうでない場合は、後者を静的メソッドとして使用します - もし
Thing
実際に変更されます(つまり、変化するプロパティがあります)、後者を推奨します。もしThing
は変更されませんが、後者も同様に許容されます。 - それ以外の場合、オブジェクトは現実世界のオブジェクトにマッピングすることを目的としているため、より現実に基づいていると思われる方法を選択してください。
OO 言語で作業していない場合でも、コード全体を読みやすくするために Thing.DoSomething() を使用し、次のような一連の関数を用意します。
thingdosomething()thingdoanthask()thingwedosomeTheselse()
それから
AnotherThingDoSomething()
などの方がはるかに優れています。
「Thing」上で動作するすべてのコードは 1 か所にあります。もちろん、「DoSomething」と他のタスクには一貫した名前を付ける必要があります。つまり、ThingOneRead()、ThingTwoRead() などになります。今までにポイントを獲得できるはずです。12 か月後にコードの作業に戻るときは、時間をかけて物事を論理的にすることに感謝するでしょう。
一般に、「何か」が「物」が自然に実行方法を知っているアクションである場合は、thing.doSomething() を使用する必要があります。これは優れた OO カプセル化です。そうしないと、DoSomethingToThing(thing) が「thing」の潜在的な内部情報にアクセスする必要があるからです。
たとえば、invoice.getTotal()
「何か」が本来「もの」のドメイン モデルの一部ではない場合、1 つのオプションはヘルパー メソッドを使用することです。
例えば:Logger.log(請求書)
オブジェクトに対する DoingSomething が別のシナリオで異なる結果を生成する可能性がある場合は、oneThing.DoSomethingToThing(anotherThing) をお勧めします。
たとえば、プログラム内に 2 つの保存オブジェクトがある場合、DatabaseObject.Save(thing) を採用する場合があります。 SessionObject.Save(thing) は、thing.Save() や thing.SaveToDatabase または thing.SaveToSession() よりも有利です。 。
パブリック プロパティを取得する場合を除き、クラスにパラメーターを渡すことはほとんどありません。
イオンの答えに付け加えると、それは物とそれに対して何をしたいかによって異なります。したがって、Thing を作成していて、DoSomething が Thing の内部状態を変更する場合、最良のアプローチは Thing.DoSomething です。ただし、アクションが内部状態を変更する以上のことを行う場合は、DoSomething(Thing) の方が合理的です。例えば:
Collection.Add(Thing)
よりも良い
Thing.AddSelfToCollection(Collection)
Thing を作成したことがなく、派生クラスを作成できない場合は、DoSomething(Thing) を実行する以外に選択肢はありません。
オブジェクト指向プログラミングでも、メソッドの代わりに関数呼び出しを使用する (または、さらに言えば、呼び出し対象以外のオブジェクトのメソッドを呼び出す) と便利な場合があります。オブジェクトに対して save() を呼び出すだけの単純なデータベース永続化フレームワークを想像してください。保存したいすべてのクラスに SQL ステートメントを含めてコードを複雑にし、コード全体に SQL を分散させ、ストレージ エンジンの変更を PITA にする代わりに、save(Class1)、save(Class2) を定義するインターフェイスを作成できます。 )など。とその実装。次に、実際には、databaseSaver.save(class1) を呼び出し、すべてを 1 か所にまとめることになります。
私は同意しなければなりません ケビン・コナー
また、2 つの形式のいずれかの呼び出し元にも注意してください。呼び出し元はおそらく、Thing に対して間違いなく何かを行う他のオブジェクトのメソッドです:)