web-dev-qa-db-ja.com

OOPのオブジェクトはエンティティを表す必要がありますか?

オブジェクトはエンティティを表す必要がありますか?

エンティティとは、ProductMotorParkingLotなど、物理的、または明確な非物理的概念的なオブジェクト-明確に定義されたもので、いくつかのコアデータはオブジェクトに明確に属しており、いくつかの関数/メソッドはコアデータを明確に操作します。

たとえば、私はDemonのオブジェクト、それ自体がエンティティ、架空のものではなく、物理的ではなくエンティティである可能性があります。

オブジェクトは、単なるメソッドのコレクションであり、共通の目的に関連する共通のプロシージャのセットになることができますか?

例:クラスはMotorOperationsまたはMotorActionsと呼ばれますが、エンティティはありませんが、クラス内のメソッドは次のようなことを行います

  • getMotorDataFromHTMLForm()
  • getMotorManufacturers()
  • selectMotorFromUserRequirements($ requirements)
  • canMotorCanHandleOperatingConditions($ conditions)
  • computePowerConsumptionForMotor($ id)

クラスは通常、オブジェクトの中心となるデータ+データの操作として定義されます。したがって、Motorの場合、モーターの仕様に関連するモーター変数がいくつかあり、それらのデータを組み合わせて何かを生成する操作が存在する可能性があります。

私の場合、データ+を通過するクラスを持つクラスがあり、「Motor」を中心とするデータはありません。オペレーション」、クラスの一時的なパススルーデータ以外。

質問

クラスはエンティティのないオブジェクトを表すことができますか?そうでない場合、なぜそれらは不良/不完全/ OOP中心ではないのですか? OOPと一致するように概念的に変更/改善する必要がある方法はありますか?

83
Dennis

いいえ、オブジェクトはエンティティを表す必要はありません。

実際、オブジェクトを物理的なエンティティとして考えるのをやめると、最終的にOOPが約束する利点を得るときになると私は主張します。

これは最良の例ではありませんが、 Coffee Makerのデザイン は、おそらく私に光が当たり始めた場所です。

オブジェクトはメッセージに関するものです。彼らは責任についてです。車、ユーザー、注文の問題ではありません。

OOこのように教えることは知っていますが、MVC、MVVM、またはMVWhateverを実行しようとするときに物事がどこに行くのかを理解することは、根本的に苛立たしいことです。ナビゲート性のために、Vehiclesに触れるものはすべてVehicle.extファイルにあることを知っておくのは素晴らしいことですが、アプリケーションがVehiclesの場合、必然的にそのファイルに3000行のスパゲッティが含まれることになります。

送信する新しいメッセージがある場合、少なくとも1つの新しいオブジェクトと、おそらくそれらのペアがあります。したがって、メソッドのバンドルに関する質問では、メッセージのバンドルについて話している可能性があると主張します。そして、それぞれが独自のオブジェクトになり、実行するのは独自の仕事です。そして、それは大丈夫です。本当に一緒にする必要があるものを分割すると、それが明らかになります。そして、あなたはそれらを組み立てます。しかし、OOを楽しみたい場合は、便宜上、すべてのメソッドを漠然とした適切な引き出しにすぐに落とすわけではありません。

関数のバッグについて話しましょう

オブジェクトは単なるメソッドのコレクションであり、オブジェクト指向であってもかまいませんが、my「ルール」はかなり厳密です。

  1. コレクションは単一の責任を持つ必要があり、その責任は「モーターに何かを行う」ほど一般的であってはなりません。私はサービス層のファサードのようなことをするかもしれませんが、私がナビゲート可能性/発見の理由で怠惰であることは、私がOO code 。

  2. すべてのメソッドは、抽象化の一貫した層にある必要があります。 1つのメソッドがMotorオブジェクトを取得し、別のメソッドがHorsepowerを返す場合、おそらく離れすぎています。

  3. オブジェクトは同じ「種類の」データで機能する必要があります。このオブジェクトは、モーター(開始/停止)に関連するもので、クランク長で処理を行います。これは、点火シーケンスを処理します。これは、html形式をとります。このデータはオブジェクトのフィールドであると考えられ、まとまりがあるように見えます。

私は通常、変換や合成を行っているときや、単に可変性について心配したくないときに、この種のオブジェクトを構築します。

オブジェクトの責任に焦点を合わせると、まとまりにつながります。オブジェクトとなるためにはある程度のまとまりが必要ですが、オブジェクトとなるためにフィールドや動作は必要ありません。これらの5つのモーターメソッドを必要とするシステムを構築している場合、これらのことを行う5つの異なるオブジェクトから始めます。共通点を見つけたので、物事をマージするか、共通の「ヘルパー」オブジェクトを使用し始めました。これにより、私はオープン/クローズドの問題に移動します。この特定の機能を抽出して、特定のファイルを再度変更する必要がなく、必要な場所で使用する方法を教えてください。

オブジェクトはメッセージに関するものです

フィールドはオブジェクトにとってかろうじて重要です-レジスタを取得および設定しても、プログラム外の世界は変わりません。他のオブジェクトと共同作業すると、作業が完了します。ただし、OO=の強みは、抽象化を作成できるため、個々の詳細すべてを一度に考える必要がないことです。リークしたり、意味のない抽象化は問題があるため、メンタルモデルに一致するオブジェクトを作成することについて、深く(多すぎるかもしれませんが)考えています。

重要な質問:なぜこれら2つのオブジェクトは互いに対話する必要があるのですか?

オブジェクトは人の臓器と考えてください。デフォルトの目的があり、気になる特定のメッセージを受け取ったときにのみ動作を変更します。

横断歩道に車が近づいているシナリオを想像してみてください。脳の物体として、私はストレッサーを検出します。私は視床下部にコルチコトロフィン放出ホルモンを送るように伝えます。下垂体はそのメッセージを受け取り、副腎皮質刺激ホルモンを放出します。副腎はそのメッセージを受け取り、アドレナリンを作ります。筋肉オブジェクトがそのアドレナリンメッセージを受け取ると、収縮します。心臓が同じメッセージを受け取るとき、それはより速く鼓動します。通りを横切って全力疾走するという複雑な振る舞いを開始するのに関与するプレイヤーのチェーン全体があり、それは重要なメッセージです。脳オブジェクトは、視床下部にアラートを送信する方法を知っていますが、最終的に動作を引き起こすオブジェクトのチェーンを知りません。同様に、心臓はアドレナリンがどこから来たのかわからない、それが現れたときに何か違うことをすることを知っているだけです。

したがって、この(simplified)の例では、副腎オブジェクトは、ACTHを取り、アドレナリンを作る方法を知っている必要があるだけです。それにはフィールドは必要ありませんが、それでも私にはオブジェクトのように見えます。

ここで、アプリケーションが通りを横切って走るように設計されている場合、下垂体と副腎オブジェクトは必要ないかもしれません。または、概念的に「下垂体モデル」と見なされるもののごく一部を実行する下垂体オブジェクトのみが必要です。これらの概念はすべて概念エンティティとして存在しますが、それはソフトウェアであり、AdrenalineSenderやMuscleContractorなどを作成して、モデルの「不完全さ」をあまり気にする必要はありません。

109
Steve Jackson

クラスはエンティティのないオブジェクトを表すことができますか?そうでない場合、なぜそれらは不良/不完全/ OOP中心ではないのですか?それらを変更/改善する必要がある方法はありますか?

要するに、あなたは何でもすることができますが、この特定のシナリオはOOP主義に反するでしょう:)

あなたが説明しているものは、「ユーティリティ」クラスと呼ばれることもあります-通常、コードのにおいの兆候です。いくつかのメソッドをまとめるために、クラスを作成しないようにします。

アプリケーション内のすべてのオブジェクトをモーターや車などの実際のエンティティにリンクする必要があるわけではありません。これらはビジネスオブジェクトです。アプリケーションでは、多くのビジネスオブジェクトを使用する可能性がありますが、リストしたものなど、ビジネスエンティティの一部ではない他の操作のために、さらにいくつかの分離が必要になります。

一般的なアーキテクチャパターンを確認する必要があります。そのうちの1つは MVC(Model-View-Controller) です。

MVCを使用してリストしたメソッドを配布する場合は、次のようにします。

View Class:

  • GetMotorDataFromHTMLForm()

モデルクラス(本質的にモーター):

  • GetMotorManufacturer()
  • CanMotorHandleOperationConditions()
  • CalculatePowerConsumption()

Controller Class(MotorsController):

  • GetAllMotors()
  • GetMotorById()
  • GetMotorByUserRequirements()

PHPを使用しているようです。調べるのに適したMVCフレームワークは Laravel です。それらの例では、メソッドがどこに属しているかをよく示しています。

メソッドが属する場所を決定する方法のもう1つのより一般的な情報源は、 [〜#〜] grasp [〜#〜] および [〜#〜 ] solid [〜#〜] 原則。

21
Alexus

クラスはエンティティのないオブジェクトを表すことができますか?

できる?はい。すべきかおそらくそうではありません-または、少なくとも、あなたが物事をどのように表現しているのかではありません。

notが物理オブジェクトを直接表す場合、実際にはオブジェクトが最適です。これは、現実がコードに適切にマッピングされることがまれであるためです。しかし、それらはまとまりのある概念またはコードオブジェクトを表す必要があります。彼らは単一のまとまった責任を表す必要があります。

接線方向に関連する一連の関数を一緒にバンドルすることは、名前空間またはモジュールであり、OOP用語のオブジェクトではありません。これらは便利な場合がありますが、同じではなく、異なる並べ替えが必要です。効果的に使用するための使用/思考の。

15
Telastyn

クラスはsomethingをモデル化する必要があります-そうでなければ、それは無意味です。ただし、モデル化されているものは、物理的な「もの」ではない場合があります。代わりに、それは「実際の」ものではないが、モデル化されているシステムを制御するために必要なものの表現である可能性があります。たとえば、信号機制御システムでは、何らかのアクションを実行する必要があることを示すために、システムのある部分から別の部分に送信される信号を表す、ある種のControlSignalクラスを使用できます。 「現実の世界」では、これらの信号は、あるボックスから別のボックスへのワイヤを介して送信される電気インパルスで構成されている場合があります。 「現実」ではないものを具体的なオブジェクトとしてモデル化するプロセスは、「具体化」と呼ばれます。

幸運を祈ります。

いいえ(タイトルは反対の質問をするために編集されました!)

例えば:

Public class MyRepository
{
    public MyObject GetObject(string id)
    {
        //get data from the DB and build an object
    }
}

または

Public class MyService
{
    public MyObject3 ProcessData(MyObject1 obj1, MyObject2 obj2)
    {
         //perform a process which is not a sole responsiblity of obj1 or obj2
    }
}

ただし、一般的にOOPの背後にある理想は、

public struct Car
{
    public Wheel[] Wheels;
}

public int CountWheelsOnCar(MyCarStruct car)
{
   return car.Wheels.Length;
}

public class Car
{
    private Wheel[] wheels;
    Public int CountWheels()
    {
        return this.wheels.Length;
    }
}
7
Ewan

オブジェクトはエンティティを表す必要がありますか?

質問:Loggerはどのエンティティを表しますか?

比喩的ではない-文字通り

OOP=学生に説明するとき、物理的な世界に類似したオブジェクトを説明することは役に立ちます。

Alan Kay -[〜#〜] oop [〜#〜]の父の1人-次のように書いた:

[...]

当初の発想には以下の部分がありました。

  • オブジェクトはネットワーク上の生物細胞や個々のコンピューターのようなものであり、メッセージとしか通信できないと思いました
  • データを取り除きたかった。

[...]

私にとってのOOPは、メッセージング、ローカルでの保持と保護のみを意味し、

状態プロセスの非表示、およびすべてのものの極端な遅延バインディング。

ほとんど信じられないほどのハードウェアアーキテクチャ。私は

セル/コンピューター全体のメタファーはデータを取り除きます

ソース

これから、オブジェクトは次のように最もよく理解されます

  • データをカプセル化/非表示にする自動オブジェクト

  • メッセージを介して他のオブジェクトと通信する

クラスはエンティティのないオブジェクトを表すことができますか?

確かに:Mathを考えてください


あなたの例について:

例:エンティティがないクラスをMotorOperationsまたはMotorActionsと呼ぶことができますが、クラス内のメソッドは次のようなことを行います

  • getMotorDataFromHTMLForm()

  • getMotorManufacturers()

  • selectMotorFromUserRequirements($ requirements)

  • canMotorCanHandleOperatingConditions($ conditions)

  • computePowerConsumptionForMotor($ id)

これらのメソッドをどこに配置するかを決定するには、responsibilitieswhoがwhatに対して責任があるかどうかを確認する必要があります。

getMotorDataFromHTMLForm()

このようなメソッドのコンテキストは、モーターオブジェクトの構築です。 formを介して取得したデータから自身を作成するのは、モーターの責任ではありません。少なくとも2つのオブジェクトが関係しています。 1つはモーターで、もう1つはモーターの作成者です。

getMotorManufacturers()

そのようなメソッドを書く典型的なコンテキストはserviceです。

selectMotorFromUserRequirements($ requirements)

これはservice- contextでも使用されます

canMotorCanHandleOperatingConditions($ conditions)

これはmotorオブジェクトへの質問です

computePowerConsumptionForMotor($ id)

これもモーター自体に最もよく聞かれる質問です。


tl; dr

物理的にオブジェクトとしてのobjectsのメタファーは、役立つよりもいらいらします。

5
Thomas Junk

現実世界で何かを視覚化することは、クラスをコーディングするときに役立ちますが、必須ではないと思います。

実際、どのようにリテラルになりたいかに応じて、私たちが扱う多くのオブジェクトには物理的な表現がまったくありません。たとえば、MVCアーキテクチャを検討してください。現実の世界では、一般的にクラスで表されているにもかかわらず、モデルやコントローラーはありません。 3つはしばしば何かを表しますが、常にそうとは限りません-しかし、先に述べたように、本当にそうしたい場合は、おそらく何かにフィットさせることができます(そして、何かが役立つことを想像できること!私は、ほとんどのオブジェクトを何らかの方法で視覚化します-何でもないあなたはこれまでに現実の世界で見たことがあるでしょう)。

主にこれらの「ルール」は、OOについて学ぶことを目的としていますOOそれを日常的にコーディングするために使用します。

ちなみにOOそれ自体は万能薬ではなく、いくつかのソリューションをコーディングする最初のパスではまったく役に立ちませんが、正しく実行すると本当に素晴らしいと思います保守しやすいコードを書くことは、おそらくソフトウェア開発で最も困難なタスクの1つであり、多くの場合(継続的なデバッグ/保守を必要とするもの)は、はるかに最も重要です。

5
Bill K

素人の言葉で

  • 記述したものをユーティリティクラスと呼びます。
  • 状態はありません。つまり、いくつかのインスタンスが必要になることはありません。
  • すべてのメソッドは静的です。つまり、すべてをパラメーターとして渡す必要があります

そのようなクラスは存在します。たとえば、Java SDKには、コレクションを操作するか、コレクションを返す静的メソッドのみで構成されるコレクションクラスがあります。

したがって、答えは「いいえ」になります。すべてのクラスをドメインエンティティからモデル化する必要があるわけではありません。

一方、OOPの実際の力は、次のようになります。OOP言語で作成されたプログラムでは、このようなクラスはほんの数ポリモーフィズムとカプセル化を行います。

飛行機を使ってある場所から別の場所に飛ぶのではなく、高速道路を走り回るようなものです。飛行機は車と同じように車輪がありますが、飛ぶことを目的としています。

3

はい、できます。ただし、基本的には、手続き型ライブラリと同じ機能を提供するクラスを作成しています。これを行う唯一の理由は、言語に手続き型モジュール(JavaまたはRuby)など)がない場合です。

手続き型モジュールを使用する言語(PHPには手続き型モジュールがあると思います)では、手続き型モジュールの使用のみを検討する場合があります。

また、クラスのインスタンスが一貫したオブジェクトを表すようにクラスを再設計することを検討することもできます。

しかし、OOであるためだけではなく、OO表記を使用して、それがあなたに余分な力を与えるときだけ使用してください!

3
Jonathan Cast

いいえ、クラスは単にインスタンス化でき、メンバーがあり、継承できるものを表すだけです。

実際、あなたの言語には静的クラスがあり、それは2回以上インスタンス化されることすらありません。

。NETのMath は、エンティティを表さない「数学」クラスの優れた例であり(数学について哲学を学びたい場合を除きます)、また偶然そのようなクラスの正当なユースケース。メソッドと2つのフィールドのみがあります(どちらも個々の定数を表します)。

同様のライブラリのクラス階層 Math.Net 、数学/数値メソッドをタイプ別にクラスにグループ化します。ここでクラスはエンティティではなく、論理的なカテゴリを表します。

私自身は、多くの場合、関連する(静的)関数のバッグ、または便利に1つの中心的な場所にグループ化された定数の束にすぎない(静的)クラスを作成することになります。これが良い設計だとは言いませんが、時にはそれが最も簡単な解決策です。

2
Superbest

あなたの質問に対する答えは、最終的には「クラス」や「エンティティ」などの用語をどれだけ正確に定義するかにかかっています。後者を明確に定義し、物理的エンティティと概念的エンティティの両方を許可しました。しかし、純粋主義者にとっての「クラス」という用語は、常に「特定の内部表現でオブジェクトをインスタンス化するためのファクトリー」であり、実用主義者にとっては、この用語は、純粋主義者によって軽視されているものJavaまたはC++のものを含みます。実用主義者がJavaやC++と言うかもしれないが、純粋主義者が彼が述べたときにアランケイが意味した意味を意味する[OOP]という用語の同上[[私はオブジェクト指向という用語を考案しました。私はC++を念頭に置いていませんでした "]( だから、「オブジェクト指向」という言葉でアランケイが実際に何を意味したのか? )。

実際的な見方をすれば、インスタンスのないユーティリティクラスを受け入れることができます。しかし、純粋主義の見方はもっと興味深い。 Kayによると、OOPは常にクラスよりも messages に重点を置いていました。だからあなたの質問に:

クラスはエンティティのないオブジェクトを表すことができますか?

いいえ。クラスclassifyオブジェクト。クラスは、定義上、newなどのメッセージを送信してオブジェクトを生成するエンティティです。オブジェクトは、クラスから作成されたエンティティです。クラスは、オブジェクトを製造し、実際に分類するために存在します。それがクラスが行うことです。クラスはオブジェクトを作成します。クラスを使用してオブジェクトを分類します。したがって、Cがインスタンス化またはサブクラス化を許可しないメソッドのバンドルである場合、Cによって分類されたオブジェクトは存在できないため、Cはクラスではありません。

そうでない場合、なぜそれらは不良/不完全/ OOP中心ではないのですか?

彼らは悪くありません。それらをクラスと呼ばないでください。メソッドのバンドル is OOPable:メソッドを呼び出すためにメッセージを送信できるものですが、オブジェクトをインスタンス化できない場合はクラスではありません。 Rubyを知っていますか? Rubyでは、moduleはメソッドのバンドルです。 classは、オブジェクトをインスタンス化できるモジュールです。 モジュールに問題はありません。しかし、クラスをモジュールと(純粋なOOP用語で)異なるものにするのは、クラスがインスタンスを持つことができるということです。モジュールはほんの一部のメソッドです。 混乱は、C++とJavaおよび他の言語が、クラスとモジュールの両方に「クラス」という用語を使用していることです

次に、特定の例の1つを確認するために、メッセージMotorOperationsを引数computePowerConsumptionForMotorとともに送信できるidクラスについて尋ねます。悪いですか?少なくとも Tell Do n't Ask Principle に違反していません。モータークラスを作成してpowerConsumptionメッセージを送信する have しますか? 100%の時間ではないかもしれませんが、そのようなことをしようとすると、コードに関するいくつかの素晴らしい洞察が得られます。または、それは悪いと思われる小さなクラスの爆発につながる可能性があります。

OOPと一致するように概念的に変更/改善する必要がある方法はありますか?

「OOPを実行する」ことが重要な場合は、相互にメッセージを送信することによって通信するコンポーネントにシステムを構築する方法を探す必要があります。それがまさにOOP /であるか、少なくともこの用語の造語家が考えていたものです。このビューでは、ユーティリティクラスはOOPではありません。しかし、一部の人々にとってはそうかもしれません。

クラスからインスタンス化された何百万もの生活、呼吸、オブジェクトから全体の大きなシステムを作成しようとすることは、いくつかのプロジェクトでうまくいくかもしれません。しかし、誤ったサウンドの人工クラスを作成している場合は、モジュールを導入する必要があります。クラスを強調し、インスタンス化可能なクラスがばかげている場合はモジュールを使用してください。

TL; DR-メソッドバンドルは必ずしも悪いわけではありません。最初にインスタンス化可能なクラスを使用してください。必要な場合にのみ「モジュール」にフォールバックします。

1
Ray Toal

オブジェクトは、凝集度の高いメソッドとデータのコレクションです。それらは相互に関連し、状態が保持されるため、クラスに属します。

これは、大規模な事前設計を使用してすべてをモデル化しようとする場合でも、オブジェクトを反復して進化させてシステムのニーズに適合するものに進化させる新しい設計でも当てはまります。

状態を保持する理由がない場合は、オブジェクトをインスタンス化する理由がない可能性があります。つまり、クラスを持つ理由がない可能性があります。使用する言語にクラスを使用する以外の名前空間を定義する機能がない限り、慣用的であるため、どのクラスを使用しても問題ありません。

このようにクラスを使用することの典型的な以外のマイナス面は考えられません。 「名前空間」をインスタンス化する必要があるため、不要なコストと複雑さを招く。このコードをサポートしている人なら誰でも、データがどこに追加の認知的負荷をかけているのか疑問に思います(おそらく1人あたり1回のコスト)。これは、追加の値がない通常とは異なる使用法です。

0
dietbuddha

与えられた例を取る:

getMotorDataFromHTMLForm()
selectMotorFromUserRequirements($requirements)

これらはMotorオブジェクトを返す「ファクトリ」メソッドのように見えます。 2番目は、要件を満たすために新しいオブジェクトを作成している、または調査しているモーターのデータベースまたはメモリ内コレクションがあることを意味します。その場合、それはその方法です。または、要件オブジェクトのメソッドにすることもできます。

getMotorManufacturers()

どこから入手していますか?それがこれがメソッドであるべきことです。

canMotorCanHandleOperatingConditions($conditions)
computePowerConsumptionForMotor($id)

これらはMotorのメソッドである必要があります。

0
pjc50