どのアプローチがより適切であるかを決定する要因は何ですか?
16 に答える
どちらにも場所があると思います。
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 の内部表現やその動作方法を変更しても、Thing とやり取りするコードを変更する必要がないからです。モノのコレクションを扱っている場合、またはいくつかのユーティリティ メソッドを記述している場合は、手続き型の DoSomethingToThing() の方が理にかなっているか、より単純である可能性があります。それでも、通常はそのコレクションを表すオブジェクトのメソッドとして表すことができます: たとえば
GetTotalPriceofThings();
対
Cart.getTotal();
それは、コードがどの程度オブジェクト指向であるかに大きく依存します。
- Thing.DoSomethingは、Thing が文の主語である場合に適しています。
- DoSomethingToThing(Thing n)は、Thing が文の目的語である場合に適しています。
- ThingA.DoSomethingToThingB(ThingB 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);
オリオンに同意しますが、決定プロセスを言い換えます。
名詞と動詞 / オブジェクトとアクションがあります。
- このタイプの多くのオブジェクトがこのアクションを使用する場合は、アクションをオブジェクトの一部にするようにしてください。
- それ以外の場合は、アクションを個別にグループ化しますが、関連するアクションを含めます。
ファイル/文字列の例が好きです。「SendAsHTTPReply」など、平均的な文字列では発生しない多くの文字列操作がありますが、特定の設定では頻繁に発生します。ただし、基本的には常にファイルを閉じることになるため (できれば)、クラス インターフェイスに Close アクションを配置することは完全に理にかなっています。
これは、エンターテイメント システムの一部を購入するようなものです。テレビのリモコンとテレビを一緒に使うのは理にかなっています。いつも一緒に使うからです。しかし、特定のビデオデッキ用の電源ケーブルをテレビにバンドルするのは奇妙です。多くの顧客はこれを使用することはありません。重要なアイデアは、このアクションがこのオブジェクトに対してどのくらいの頻度で使用されるかです。
イオンの答えに加えて、それは物事とあなたがそれに何をしたいかに依存します。したがって、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.something」または同等の構造をサポートしているかどうかによって異なります (つまり、OO 言語です)。もしそうなら、それは OO パラダイムであるため、はるかに適切です (メンバーは、それらが作用するオブジェクトに関連付けられる必要があります)。もちろん、手続き型のスタイルでは、DoSomethingtoThing() が唯一の選択肢です... または ThingDoSomething()
DoSomethingToThing(Thing n) はより機能的なアプローチになりますが、 Thing.DoSomething() はよりオブジェクト指向のアプローチになります。
それがオブジェクト指向と手続き型プログラミングの選択です:)
十分に文書化された OO の利点が Thing.DoSomething() に適用されると思います
考慮すべきいくつかの要因を次に示します。
Thing
クラスを変更または拡張できますか。そうでない場合は、前者を使用してくださいThing
インスタンス化できます。そうでない場合は、後者を静的メソッドとして使用します- 実際に変更される場合
Thing
(つまり、変更されるプロパティがある場合) は、後者を優先します。が変更されていない場合Thing
は、後者も同様に受け入れられます。 - それ以外の場合、オブジェクトは現実世界のオブジェクトにマッピングすることを意図しているため、より現実に基づいていると思われる方法を選択してください。
Thing.DoSomething() があるオブジェクト指向言語で作業していなくても、コードの全体的な読みやすさのために、次のような一連の関数を使用します。
ThingDoSomething() ThingDoAnotherTask() ThingWeDoSomethingElse()
それから
アナザーシングドゥサムシング()
など、はるかに優れています。
「モノ」で機能するすべてのコードが 1 つの場所にあります。もちろん、「DoSomething」やその他のタスクには一貫した名前を付ける必要があります。そのため、ThingOneRead()、ThingTwoRead() が作成されています。12 か月後にコードの作業に戻ると、時間を取って物事を論理的にすることに感謝するでしょう。
一般に、「何か」が「もの」が自然に実行方法を知っているアクションである場合は、thing.doSomething() を使用する必要があります。そうしないと、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() よりも有利になります。 .
パブリック プロパティを取得する場合を除き、クラスにパラメーターを渡すことはめったにありません。