「SomeClass」や「SomeClassInfo」など、「Info」という接尾辞を持つクラスの命名の背後にある考え方は何ですか?


20

私は物理デバイスを扱うプロジェクトに取り組んでおり、このプロジェクトのいくつかのクラスに適切な名前を付ける方法として混乱しています。

実際のデバイス(センサーとレシーバー)を考慮することと、ソフトウェアでそれらを表現することは別のことであるため、「Info」という接尾辞の名前パターンでクラスに名前を付けることを考えています。

たとえば、a Sensorは実際のセンサーを表すクラスですが(実際に動作するデバイスに実際に接続されている場合)、SensorInfoそのようなセンサーの特性のみを表すために使用されます。たとえば、ファイルの保存時に、をシリアル化するのではSensorInfoなく、ファイルヘッダーにをシリアル化しますSensor。これは意味がありません。

しかし、今私は混乱しています。なぜなら、オブジェクトのライフサイクルには、どちらを使用するべきか、どのように別のものを取得するか、または両方のバリアントを実際に1つのクラスのみに折りたたむかどうかを判断できない中間点があるためです。

また、あまりにも一般的なEmployeeクラスの例は、明らかに実在の人物の表現にすぎませんがEmployeeInfo、私の知る限り、クラスに名前を付けることを提案する人はいません。

私が使用している言語は.NETです。この命名パターンは、これらのクラスの例として、フレームワーク全体で共通しているようです。

  • DirectoryおよびDirectoryInfoクラス;
  • FileおよびFileInfoクラス;
  • ConnectionInfoクラス(対応するConnectionクラスなし);
  • DeviceInfoクラス(対応するDeviceクラスなし);

だから私の質問は次のとおりです。この命名パターンを使用することについて共通の根拠がありますか?名前のペア(ThingThingInfo)を使用するのが理にかなっている場合ThingInfoや、Thingクラスが存在しない、またはクラスが存在しない他の場合がありますか?


5
ベン・アーロンソンは、以下の彼の答えでそれを正しく理解した。Info接尾辞は区別staticそのステートフル相手方からのユーティリティメソッドを含むクラスを。それ自体は「ベストプラクティス」ではありません。これは、特定の問題を解決するために.NETチームが考案した方法にすぎません。彼らは同じように簡単に出ている可能性FileUtilityFile、しかし、File.DoSomething()そしてFileInfo.FileNameより良い読みしているようです。
ロバートハーヴェイ

1
これは一般的なパターンですが、言語やAPIと同じ数の異なる命名規則があることに注意してください。たとえば、Javaでは、ステートフルクラスがある場合Foo、インスタンス化できないユーティリティクラスがありFoosます。ネーミングに関しては、重要なことはAPI内の一貫性であり、理想的にはプラットフォーム上のAPI全体です。
ケビンクルムウィーデ

1
本当に?「クラスにEmployeeInfoという名前を付けることを提案する人はいません」?? 誰?それは、それほど明白ではない何かに対して少し強いようです。
ThePopMachine

@ThePopMachineこの場合、「誰も」という言葉は難しいかもしれないことに同意しますが、Employee例はオンラインまたは古典的な本で数十人に発見されていますが、私はまだ見てEmployeeInfoいません(おそらく従業員は生きているからです接続やファイルなどの技術的な構成要素)。しかし、EmployeeInfoプロジェクトでクラスが提案されることになった場合、それを使用できると思います。
-heltonbiker

回答:


21

「情報」は間違った呼び名だと思います。オブジェクトには状態とアクションがあります。「情報」は、OOPに既に組み込まれている「状態」の別名です。

ここで実際にモデル化しようとしているのは何ですか?他のコードが使用できるように、ソフトウェアのハードウェアを表すオブジェクトが必要です。

それは言うのは簡単ですが、あなたが知ったように、それ以上のものがあります。「ハードウェアの表現」は驚くほど広範です。それを行うオブジェクトには、いくつかの懸念があります。

  • USBインターフェイス、シリアルポート、TCP / IP、または独自の接続と通信しているかどうかにかかわらず、低レベルのデバイス通信。
  • 状態の管理。デバイスの電源は入っていますか?ソフトウェアと話す準備はできましたか?忙しい?
  • イベントの処理。デバイスはデータを生成しました:関心のある他のクラスに渡すイベントを生成する必要があります。

センサーなどの特定のデバイスは、プリンター/スキャナー/ FAX多機能デバイスよりも懸念が少なくなります。センサーはビットストリームを生成するだけですが、複雑なデバイスには複雑なプロトコルと相互作用があります。

とにかく、特定の質問に戻って、特定の要件とハードウェア相互作用の複雑さに応じて、これを行う方法がいくつかあります。

温度センサーのクラス階層をどのように設計するかの例を次に示します。

  • ITemperatureSource:温度データを生成できるものすべてを表すインターフェイス:センサー、ファイルラッパーまたはハードコードされたデータ(考えられる:模擬テスト)。

  • Acme4680Sensor:ACMEモデル4680センサー(Roadrunnerが近くにあることを検出するのに最適)。これにより、複数のインターフェイスを実装できます。おそらく、このセンサーは温度と湿度の両方を検出します。このオブジェクトには、「センサーは接続されていますか?」などのプログラムレベルの状態が含まれます。そして「最後の読書は何でしたか?」

  • Acme4680SensorComm:物理デバイスとの通信のみに使用れます。多くの状態を維持しません。メッセージの送受信に使用されます。ハードウェアが理解するメッセージごとにC#メソッドがあります。

  • HardwareManager:デバイスの取得に使用されます。これは、本質的にインスタンスをキャッシュするファクトリです。各ハードウェアデバイスに対応するデバイスオブジェクトのインスタンスは1つだけです。スレッドAがACME温度センサーを要求し、スレッドBがACME湿度センサーを要求する場合、これらは実際には同じオブジェクトであり、両方のスレッドに返される必要があることを知るのに十分スマートでなければなりません。


最上位には、各ハードウェアタイプのインターフェイスがあります。これらは、C#データ型を使用して、C#コードがデバイス上で実行するアクションを記述します(rawデバイスドライバーが使用する可能性のあるバイト配列など)。

同じレベルで、ハードウェアタイプごとに1つのインスタンスを持つ列挙クラスがあります。温度センサーには1つのタイプ、湿度センサーには別のタイプがあります。

これより1つ下のレベルは、これらのインターフェイスを実装する実際のクラスです。これらは、前述のAcme4680Sensorに似た1つのデバイスを表します。デバイスが複数の機能を実行できる場合、特定のクラスは複数のインターフェイスを実装できます。

各デバイスクラスには、ハードウェアと通信する低レベルのタスクを処理する独自のプライベートComm(通信)クラスがあります。

ハードウェアモジュールの外側で表示される唯一のレイヤーは、interfaces / enumとHardwareManagerです。HardwareManagerクラスは、ハンドル(あなたがインスタンスをキャッシュデバイスクラスのインスタンス化、という工場の抽象化され、実際に同一のハードウェアデバイスに話を2つのデバイスクラスを望んでいないが)、センサーの特定のタイプを必要とするなどのAクラスを取得するためにHardwareManagerを頼みます特定の列挙型のデバイス。それが既にインスタンス化されているかどうか、そうでない場合は作成して初期化する方法などを把握します。

ここでの目標は、ビジネスロジックを低レベルのハードウェアロジックから分離することです。センサーデータを画面に出力するコードを作成する場合、そのコードは、これらのハードウェアインターフェイスを中心とするこの分離が行われている場合にのみ、どのタイプのセンサーを使用してかまいません。


この回答で説明されている設計を示すUMLクラス図の例

注:図が矢印のスープに変わってしまうため、HardwareManagerと描画しなかった各デバイスクラスの間に関連付けがあります。


非常に興味深い答えです。簡単な編集をお願いします。あなたが言及した4つのクラスの間の継承/包含/コラボレーションをより明確にしておきます。どうもありがとうございました!
heltonbiker

UMLクラス図を追加しました。これは役立ちますか?

2
これはキラーな答えだと思うし、それは私を大いに助けるだけでなく、将来もっと多くの人々を助けることができると信じている。その上、あなたが提供するクラス階層の例は、私たちの問題と解決策の領域を非常によくマップしています。どうもありがとうございました!
heltonbiker

私が質問を読んだとき、私はさらに進んでいることに気づいたので、少しやり過ぎて、デザイン全体を共有しました。名前は設計を示しているため、これは単なる命名の問題以上のものです。私はこの方法で構築されたシステムを使用してきましたが、かなりうまく機能しました。

11

これらのクラスは、名前空間の数の上に広がっているので、ここで、単一の統一規則を見つけるには少し難しいかもしれない、(ConnectionInfoであるように思わCrystalDecisionsれ、DeviceInfoSystem.Reporting.WebForms)。

ただし、これらの例を見ると、接尾辞には2つの明確な用途があるようです。

  • 静的メソッドを提供するクラスとインスタンスメソッドを提供するクラスを区別します。これは、System.IOクラスの説明で強調されているとおりです。

    ディレクトリ

    ディレクトリおよびサブディレクトリを作成、移動、列挙するための静的メソッドを公開します。このクラスは継承できません。

    DirectoryInfo

    ディレクトリとサブディレクトリを作成、移動、列挙するためのインスタンスメソッドを公開します。このクラスは継承できません。

    Infoここでは少し奇妙な選択のように見えますが、違いは比較的明確になっています:Directoryクラスは、特定のディレクトリを合理的に表すか、状態を保持せずに一般的なディレクトリ関連のヘルパーメソッドを提供DirectoryInfoできますが、実際は前者だけです。

  • クラスは情報のみを保持し、接尾辞のない名前から合理的に予想される動作提供しないことを強調します。

    私はその文の最後の部分は、区別が、言うことをパズルの一片であるかもしれないと思うConnectionInfoからEmployeeInfo。というクラスがあった場合Connection、接続が持っている機能を実際に提供することを合理的に期待していますvoid Open()-などのメソッドを探していますが、Employeeクラスが実際にできると期待する人は誰もいません本物は何をEmployee行い、等の方法を探しvoid DoPaperwork()たりbool TryDiscreetlyBrowseFacebook()


1
ご回答どうもありがとうございました!あなたの答えの最初の箇条書きは.NETクラスで何が起こっているかを明確に説明していると思いますが、2番目の箇条書きはより意図された抽象化を明らかにするため、より価値があります(ちなみに異なります)。説明するもの。どの回答を受け入れるかを選択するのは困難でした。
heltonbiker

4

一般的に、Infoオブジェクトはある時点でのオブジェクトの状態に関する情報をカプセル化します。システムにファイルを調べて、FileInfoそのサイズに関連付けられたオブジェクトを提供するように依頼すると、そのオブジェクトは、リクエストが与えられた時点でのファイルのサイズ(または、より正確には、呼び出しが行われてから戻るまでのある時点でのファイル)。リクエストが返されてからFileInfoオブジェクトが検査されるまでの間にファイルのサイズが変化する場合、そのような変化がオブジェクトに反映されるとは思われませんFileInfo

この動作はFileオブジェクトの動作とは非常に異なることに注意してください。非排他モードでディスクファイルを開く要求がプロパティFileを持つオブジェクトを生成する場合SizeFileオブジェクトは単にディスクの状態を表すだけではないため、ディスクファイルのサイズが変更されると、返される値が変更されることを期待しますファイル- ファイル自体を表します

多くの場合、リソースに接続するオブジェクトは、サービスが不要になったときにクリーンアップする必要があります。ので*Info、オブジェクトがリソースに接続していない、彼らはクリーンアップを必要としません。結果として、Infoオブジェクトがクライアントの要件を満たしている場合、基礎となるリソースを表すがそのリソースへの接続をクリーンアップする必要があるオブジェクトを使用するよりも、コードに1つを使用させる方がよい場合があります。


1
これは正確に間違っているわけではありませんが、Fileクラスをインスタンス化できず、FileInfoオブジェクト基礎となるファイルシステムで更新するため、.NETの命名パターンをまったくうまく説明していないようです。
ネイサンタギー

@NathanTuggyこれは.NETのこの命名規則とはあまり関係がないことに同意しますが、私の現在の問題に関しては、それは非常に関連性があり、一貫した解決策をもたらすことができると思います。私はこの答えを支持しましたが、受け入れるために1つだけを選ぶのは難しいです
...-heltonbiker

@NathanTuggy:あらゆる一貫性のモデルとして.NETを使用することはお勧めしません。それは多くの良いアイデアをカプセル化する良い有用なフレームワークですが、いくつかの悪いアイデアも同様にミックスに取り込まれます。
supercat

@supercat:もちろん。「.NETがなぜこれを行うのか」という質問に答えるのは奇妙に思えます。「%THIS_WAY%を実行することをお勧めします」と。
ネイサンタギー

@NathanTuggy:問題のクラスの正確な詳細を覚えていませんでしたが、FileInfo静的にキャプチャされた情報を保持していると思いました。ありませんか?また、ファイルを非排他モードで開く機会は一度もありませんでしたが、可能であるべきであり、開くために使用されるオブジェクトが呼ばれるFile(通常、私はちょうど使用しReadAllBytesWriteAllBytesReadAllTextWriteAllText、など)。
スーパーキャット

2

実際のデバイス(センサーとレシーバー)を考慮することと、ソフトウェアでそれらを表現することは別のことであるため、「Info」という接尾辞の名前パターンでクラスに名前を付けることを考えています。

たとえば、a Sensorは実際のセンサーを表すクラスですが(実際に動作するデバイスに実際に接続されている場合)、SensorInfoそのようなセンサーの特性のみを表すために使用されます。たとえば、ファイルの保存時に、をシリアル化するのではSensorInfoなく、ファイルヘッダーにをシリアル化しますSensor。これは意味がありません。

私はこの区別が好きではありません。すべてのオブジェクトは「ソフトウェアの表現」です。それが「オブジェクト」という言葉の意味です。

ここで、周辺機器に関する情報を、周辺機器とインターフェイスする実際のコードから分離することが理にかなっている場合があります。したがって、たとえば、SensorにはSensorInfoがあります。これには、ほとんどのインスタンス変数と、ハードウェアを必要としないメソッドが含まれています。一方、Sensorクラスは実際に物理センサーと対話します。Sensorコンピューターにセンサーが搭載されていない限り、持っているわけではありませんが、おそらく持っている可能性がありSensorInfoます。

問題は、この種の設計を(ほぼ)すべてのクラスに一般化できることです。ですから、注意する必要があります。SensorInfoInfoたとえば、明らかにクラスはありません。また、Sensor変数がある場合、そのメンバーと対話することでデメテル法則に違反していることに気付くかもしれませんSensorInfo。もちろんこれは致命的ではありませんが、APIの設計はライブラリ作成者だけのものではありません。独自のAPIを簡潔で​​シンプルに保つと、コードの保守性が向上します。

私の意見では、ディレクトリのようなファイルシステムリソースはこの端に非常に近いです。ローカルにアクセスできないディレクトリを記述したいという状況もありますが、平均的な開発者はおそらくそのような状況にはありません。私の意見では、この方法でクラス構造を複雑にすることは役に立ちません。Pythonのアプローチとの対比pathlib:「必要な可能性が最も高い」単一のクラスと、ほとんどの開発者が安全に無視できるさまざまな補助クラスがあります。ただし、本当に必要な場合は、具体的なメソッドを取り除いただけで、ほぼ同じインターフェースが提供されます。


あなたの答えに感謝し、あなたの「have-a」コンストラクトに感謝​​します;)あなたの答えは、「DTO」(データ転送オブジェクト)コンセプトまたはその兄弟である眉をひそめているパラメータオブジェクトによって引き起こされる不快感を思い出させます。通常はメソッドを含まないため、より正統的なオブジェクト指向の熱狂者です(結局それはデータ転送オブジェクトです)。その意味で、他の人が言ったことも要約するSensorInfoと、実際のSensorオブジェクトのデータ/状態部分のみを表すDTOのよ​​うなもの、および/または「スナップショット」、または「仕様」のようなものになると思います「そこにさえないかもしれない」。
heltonbiker

ほとんどのデザインの問題と同様に、厳格なルールはありません。私が提供したpathlibの例では、PureWindowsPathInfoオブジェクトのように少し動作しますが、Windowsシステムを必要としない処理(サブディレクトリの取得、ファイル拡張子の分割など)を行うメソッドがあります。これは、単に装飾された構造体を提供するよりも便利です。
ケビン

1
繰り返しになりますが、 "glorified struct"の部分の栄誉は:)です。それは、ボブおじさんの「Clean Code」本の第6章からの関連する引用を思い出させます。「成熟したプログラマーは、すべてがオブジェクトであるという考えは神話であることを知っています。
heltonbiker

2

高レベルのビジネスロジックコードと低レベルモデル、アーキテクチャコンポーネントなどがあるため、コンテキスト/ドメインが重要だと思います...

「Info」、「Data」、「Manager」、「Object」、「Class」、「Model」、「Controller」などは、すべてのオブジェクトに何らかの情報またはデータがあるため、特に下位レベルでは臭いサフィックスになる可能性があります。その情報は必要ありません。

ビジネスドメインのクラス名は、奇妙に聞こえるか、100%正しい言語であるかどうかに関係なく、すべての利害関係者が話しているようにする必要があります。

データ構造の適切な接尾辞は、たとえば「リスト」、「マップ」、ヒントパターンの「デコレータ」、「アダプタ」が必要だと思う場合です。

あなたのセンサーのシナリオに、私は期待していないSensorInfo、あなたのセンサーが何であるかを保存するために、しかしSensorSpecInfoimhoはFileInfo、サイズ、保存しないファイルパス、ファイル名などから派生した情報のような、より派生した情報です。

別のポイント:

コンピューターサイエンスには、キャッシュの無効化と命名という2つの困難なことがあります。

-フィルカールトン

それは、ほんの数秒間名前について考えることを常に思い出させます。もし見つからなかったら、奇妙な名前を使用し、「TODO」マークを付けます。私のIDEはリファクタリングのサポートを提供するため、後でいつでも変更できます。それは良いものでなければならない会社のスローガンではありませんが、私たちが望むたびに変更できるほんの一部のコードです。心に留めておきます。


1

ThingInfoは、Thingの優れた読み取り専用プロキシとして機能します。

http://www.dofactory.com/net/proxy-design-patternを参照してください

プロキシ:「サロゲートまたはプレースホルダーを提供して、別のオブジェクトへのアクセスを制御します。」

通常、ThingInfoにはセッターのないパブリックプロパティがあります。これらのクラスおよびクラスのメソッドは安全に使用でき、バッキングデータ、オブジェクト、または他のオブジェクトへの変更をコミットしません。状態の変更やその他の副作用は発生しません。これらは、レポートやWebサービス、またはオブジェクトに関する情報を必要とするが実際のオブジェクト自体へのアクセスを制限したい場所に使用できます。

ThingInfoは可能な限り使用し、実際のThingの使用を、Thingオブジェクトを実際に変更する必要がある時間に制限します。このパターンの使用に慣れると、読み取りとデバッグがかなり速くなります。


優れた。本日、私は質問で使用したクラスに関して、アーキテクチャのニーズを分析していましたが、これとまったく同じ結論に達しました。私の場合、Receiver多くSensorのからデータストリームを受信するがあります。アイデアは、受信機が実際のセンサーを抽象化することです。しかし問題は、センサー情報をファイルヘッダーに書き込むために必要です。解決策:それぞれIReceiverにのリストがありSensorInfoます。センサーの状態を変更することを意味するコマンドをレシーバーに送信すると、これらの変更は(ゲッターを介して)それぞれに反映されますSensorInfo
heltonbiker

(続き...)つまり、センサー自体とは通信せず、より高いレベルのコマンドを介してレシーバーとのみ通信し、レシーバーは各センサーと順番に通信します。しかし、最終的にはセンサーからの情報が必要になりList<SensorInfo>ます。これは、Receiverインスタンスからその読み取り専用プロパティを介して取得します。
heltonbiker

1

これまでのところ、この質問の誰も、この命名規則の本当の理由を理解していないようです。

AはDirectoryInfoないディレクトリ。これは、あるデータでDTO についてディレクトリ。同じディレクトリを記述するこのようなインスタンスが多数存在する場合があります。エンティティではありません。これはスローアウェイ値オブジェクトです。A は実際のディレクトリを表していません。また、ディレクトリのハンドルまたはコントローラーと考えることもできます。DirectoryInfo

これを、という名前のクラスと比較してくださいEmployee。これはORMエンティティオブジェクトである場合があり、その従業員を記述する単一のオブジェクトです。アイデンティティのない値オブジェクトである場合は、を呼び出す必要がありますEmployeeInfoEmployee確かに、実際の従業員を表しありません。呼び出される値のようなDTOクラスEmployeeInfoは、明らかに従業員を表すのではなく、それを記述するか、データを保存します。

実際には、両方のクラスが存在するBCLの例があります。A ServiceControllerはWindowsサービスを記述するクラスです。サービスごとにこのようなコントローラーをいくつでも設定できます。A ServiceBase(または派生クラス)がある実際のサービスとは概念的に異なるサービスごとに、それの複数のインスタンスを持っている意味がありません。


これProxyは@Shmokenが言及したパターンに似ていますね。
heltonbiker

@heltonbikerは必ずしもプロキシである必要はありません。それは、それが記述しているものにいかなる方法でも接続されていないオブジェクトである可能性があります。たとえばEmployeeInfo、Webサービスから取得する場合があります。それはプロキシではありません。さらなる例:アドレスはエンティティではないため、プロキシすることができるものAddressInfoすらありません。これはスタンドアロンの値です。
usr

1
なるほど、理にかなっています!
heltonbiker
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.