「新しい」キーワードを使用する必要がある場合と使用しない場合


15

Misko HeveryによるUnit Testingに関するGoogle Tech Talkのプレゼンテーションを見て、彼newはビジネスロジックコードでキーワードを使用しないように言った。

プログラムを作成し、newキーワードをあちこちで使用することになりましたが、それらは主にデータを保持するオブジェクトをインスタンス化するためのものでした(つまり、関数やメソッドはありませんでした)。

私は自分のプログラムに新しいキーワードを使用したときに何か間違ったことをしたのだろうかと思っています。そして、その「規則」をどこで破ることができるでしょうか?


2
プログラミング言語に関連するタグを追加できますか?Newは多くの言語(C ++、Java、Rubyなど)に存在し、セマンティクスが異なります。
sakisk

回答:


16

これは、厳格なルールよりもガイダンスです。

実動コードで「新規」を使用することにより、クラスとその協力者を結び付けます。誰かが他のコラボレーター、たとえば単体テスト用のある種のモックコラボレーターを使用したい場合、コラボレーターはビジネスロジックで作成されるため使用できません。

もちろん、誰かがこれらの新しいオブジェクトを作成する必要がありますが、これは多くの場合、Springなどの依存性注入フレームワーク、またはコンストラクターを介して注入されたビジネスロジッククラスをインスタンス化するクラスの2つの場所のいずれかに任せるのが最善です。

もちろん、これはやりすぎです。新しいArrayListを返したい場合は、おそらく大丈夫です-特にこれが不変のListになる場合。

あなたが自問すべき主な質問は、「このタイプのオブジェクトを作成するコードのこの部分の主な責任は、それとも私が合理的に他の場所に移動できる実装の詳細ですか?」です。


1
それを不変のリストにしたい場合はCollections.unmodifiableList、何かを使用する必要があります。しかし、私はあなたの意味を知っています:)
MatrixFrog

はい、しかし、あなたはその後、変更不可能であることに変換元のリストを作成するために何とか必要があります...
ビル・ミッチェル

5

この質問の要点は最後にあります。プログラムに新しいキーワードを使用したときに何か間違ったことをしたのでしょうか。そして、その「規則」をどこで破ることができるでしょうか?

コードに対して効果的な単体テストを作成できれば、何も間違ったことはありません。を使用しnewてコードの単体テストが困難または不可能になった場合は、newの使用を再評価する必要があります。この分析を他のクラスとの相互作用に拡張することもできますが、多くの場合、堅牢な単体テストを作成する能力は十分なプロキシです。


5

要するに、「new」を使用するときはいつでも、このコードを含むクラスを作成中のオブジェクトに緊密に結合します。これらのオブジェクトの1つをインスタンス化するために、インスタンス化を行うクラスは、インスタンス化される具象クラスを知っている必要があります。そのため、「新規」を使用する場合、インスタンス化を配置するクラスがその知識が存在する「良い」場所であるかどうかを検討する必要があります。インスタンス化されているオブジェクトが変更されました。

密結合、つまり別の具体的なクラスの知識を持つオブジェクトは、常に回避されるべきではありません。あるレベルでは、どこかから何かのコピーを与えられて他のすべてのものがオブジェクトを扱う場合でも、このオブジェクトを作成する方法を知っている必要があります。ただし、作成中のクラスが変更された場合、そのクラスの具体的な実装を知っているクラスは、そのクラスの変更を正しく処理するように更新する必要があります。

あなたが常に尋ねるべき質問は、「このクラスにこの他のクラスを作成する方法を知ってもらうことは、アプリをメンテナンスする際の責任になりますか?」です。両方の主要な設計手法(SOLIDとGRASP)は、微妙に異なる理由で、通常「はい」と答えます。ただし、これらは方法論にすぎず、どちらも独自のプログラムの知識に基づいて定式化されていないという極端な制限があります。そのため、注意が必要なのは誤りであり、密結合のポイントがあると、このポイントの片側または両側に変更を加えることに関連する問題が発生する可能性があると想定しています。3つのことを知って最終決定を下す必要があります。理論上のベストプラクティス(何かが変化する可能性があるため、すべてを疎結合すること)。理論的なベストプラクティスを実装するコスト(1つのタイプの変更を緩和し、別のタイプの変更を妨げる抽象化のいくつかの新しいレイヤーを含む場合があります)。そして、あなたが予想している変化のタイプがこれまでに必要になるという現実世界の確率。

一般的なガイドライン:

  • コンパイルされたコードライブラリ間の密結合を避けます。DLL(またはEXEとそのDLL)間のインターフェイスは、密結合が不利になる主な場所です。DLL XのクラスAを変更し、メインEXEのクラスBがクラスAを認識している場合、両方のバイナリを再コンパイルしてリリースする必要があります。単一のバイナリ内では、変更を行うためにバイナリ全体を再構築する必要があるため、通常、より密な結合が許容されます。複数のバイナリを再構築することが避けられない場合もありますが、特に帯域幅が限られている状況(モバイルアプリの展開など、アップグレードで新しいDLLをプッシュする方がはるかに安価な場合)で、可能な限り回避できるようにコードを構成する必要がありますプログラム全体をプッシュするよりも)。

  • プログラムの主要な「ロジックセンター」間の密結合を避けます。よく構造化されたプログラムは、水平スライスと垂直スライスで構成されていると考えることができます。水平スライスは、UI、コントローラー、ドメイン、DAO、データなどの従来のアプリケーション層です。垂直スライスは、個々のウィンドウまたはビュー、または個々の「ユーザーストーリー」(基本的なタイプの新しいレコードの作成など)に対して定義できます。適切に構造化されたシステムで上下左右に移動する呼び出しを行う場合、通常、その呼び出しを抽象化する必要があります。たとえば、検証でデータを取得する必要がある場合は、DBに直接アクセスする必要はありませんが、データ取得のためのインターフェイスを呼び出す必要があります。一部のUIコントロールが別のウィンドウを含む高度なロジックを実行する必要がある場合、イベントやコールバックを介してこのロジックのトリガーを抽象化する必要があります。結果として何が行われるかを知る必要がないため、それをトリガーするコントロールを変更せずに何を行うかを変更できます。

  • いずれにせよ、変更がどれだけ簡単または難しいか、そしてその変更がどれほど起こりそうかを考えてください。作成中のオブジェクトが1か所からしか使用されておらず、変更することを予見しない場合、一般に密結合はより許容され、この状況では疎結合よりも優れている場合があります。疎結合には抽象化が必要です。抽象化は、依存関係の実装を変更する必要がある場合に依存オブジェクトへの変更を防ぐ追加のレイヤーです。ただし、インターフェイス自体を変更する必要がある場合(新しいメソッド呼び出しの追加、または既存のメソッド呼び出しへのパラメーターの追加)、インターフェイスは実際に変更を行うために必要な作業量を増やします。さまざまな種類の変更が設計に影響を与える可能性を検討する必要がありますが、


3

データのみを保持するオブジェクト、またはDTO(データ転送オブジェクト)は問題なく、1日中作成します。newアクションを実行するクラスで回避したい場合は、代わりにインターフェースに対してプログラミングする消費側クラスが必要です。そこでは、ロジックを呼び出して消費することができますが、ロジックを含むクラスのインスタンスを実際に作成する責任はありません。これらのアクション実行またはクラスを含むロジックは依存関係です。Miskoの講演は、これらの依存関係を注入し、他のエンティティに実際に作成する責任を負わせることを対象としています。


2

他の人たちはすでにこの点に言及していますが、概念を理解しやすくするために、ボブおじさん(ボブ・マーティン)のきれいなコードから引用したかったのです。

「構造を使用から分離するための強力なメカニズムは、依存性注入(DI)、制御反転(IoC)を依存性管理に適用することです。単一責任の原則。依存関係の管理のコンテキストでは、オブジェクトが依存関係自体をインスタンス化するための責任を取るべきではありません。その代わり、それによってコントロールを反転、別の「権威」機構にこの責任を渡す必要があります。セットアップは、世界的な関心事であるので、この信頼できるメカニズムは、通常「メイン」ルーチンまたは専用コンテナのいずれかです。

このルールに従うことは常に良い考えだと思います。他の人は、より重要なIMOに言及しました->それは、クラスをその依存関係から切り離します(共同作業者)。2番目の理由は、クラスがより小さく、より簡潔になり、理解しやすくなり、他のコンテキストでも再利用できるようになることです。

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