12

次のようなクラスがあるとします。

internal class SomeClass
{
    IDependency _someDependency;

    ...


    internal string SomeFunctionality_MakesUseofIDependency()
    {
    ...
    }
}

そして、関連しているが、その目的を達成するために別の依存関係を利用する機能を追加したいと考えています。おそらく、次のようなものです。

internal class SomeClass
{
    IDependency _someDependency;

    IDependency2 _someDependency2;

    ...


    internal string SomeFunctionality_MakesUseofIDependency()
    {
    ...
    }

    internal string OtherFunctionality_MakesUseOfIDependency2()
    {
    ...
    }
}

この新しい機能の単体テストを作成する (または既存の機能の単体テストを更新する) と、必要のない依存関係に null を渡しながら、SomeClass (SUT) の新しいインスタンスを作成していることに気付きます。私がテストしようとしている特定の機能について。

これは私には悪臭のように思えますが、私がこの道をたどる理由は、導入する新しい機能の各部分に対して新しいクラスを作成していることに気付いたからです。これも悪いことのように思えたので、同様の機能をグループ化する試みを始めました。

私の質問: クラスのすべての依存関係は、そのすべての機能によって消費されるべきですか?

4

6 に答える 6

11

すべてのインスタンス メソッドがすべてのインスタンス変数に触れると、クラスは最大限にまとまります。どのインスタンス メソッドもインスタンス変数を他のメソッドと共有しない場合、クラスの凝集性は最小限になります。団結力が高いことが望ましいのは事実ですが、80-20 ルールが適用されることも事実です。結束力の最後のわずかな増加を得るには、途方もない努力が必要になる場合があります。

一般に、一部の変数を使用しないメソッドがある場合、それは臭いです。しかし、クラスを完全にリファクタリングするには、わずかな臭いだけでは十分ではありません。これは懸念すべきことであり、監視する必要がありますが、すぐに行動することはお勧めしません.

于 2009-07-14T16:13:26.387 に答える
3

SomeClass は内部状態を維持しますか?それとも、さまざまな機能を単に「組み立てる」だけですか? そのように書き直すことができますか:

internal class SomeClass
{
    ...


    internal string SomeFunctionality(IDependency _someDependency)
    {
    ...
    }

    internal string OtherFunctionality(IDependency2 _someDependency2)
    {
    ...
    }
}

この場合、SomeFunctionality と OtherFunctionality が何らかの形で (機能的に) 関連していて、プレースホルダーを使用しても明らかでない場合、SRP を壊すことはできません。

また、作成/DI 時ではなく、クライアントから使用する依存関係を選択できるという付加価値があります。これらのメソッドのユースケースを定義するいくつかのテストは、状況を明確にするのに役立つかもしれません: 両方のメソッドが同じオブジェクトで呼び出される意味のあるテストケースを書くことができれば、SRP を壊すことはありません。

Facade パターンに関しては、50 以上のメソッド クラスになってしまうと、好きになれないほど乱暴になっているのを何度も見てきました... 問題は、なぜそれが必要なのかということです。効率的な理由から昔ながらの EJB 風?

于 2009-07-14T06:27:44.177 に答える
0

クラスにカプセル化できる共有状態をメソッドが使用する場合、私は通常、メソッドをクラスにグループ化します。クラス内のすべてのメソッドで使用されていない依存関係を持つことは、コードのにおいがする可能性がありますが、それほど強いものではありません。私は通常、クラスが大きくなりすぎたり、クラスに依存関係が多すぎたり、メソッドに共有状態がない場合にのみ、クラスからメソッドを分割します。

于 2009-07-13T09:41:39.907 に答える
0

私の質問: クラスのすべての依存関係は、そのすべての機能によって消費されるべきですか?

これは、クラスが少し一貫性がない (「複数のことを行う」) 可能性があることを示すヒントですが、あなたが言うように、これをやりすぎると、新しい機能のすべての部分に対して新しいクラスが作成されます。 . そのため、ファサード オブジェクトを導入してそれらを再びまとめることをお勧めします (ファサード オブジェクトは、この特定の設計規則とは正反対のようです)。

自分 (およびチームの他のメンバー) にとって適切なバランスを見つける必要があります。

于 2009-07-13T09:42:14.073 に答える
0

Facade は、複雑さを隠したい場合 (レガシー システムへのインターフェースなど) や、インターフェースの観点から後方互換性を維持しながら機能を統合したい場合に使用されます。

あなたの場合の鍵は、同じクラスに2つの異なるメソッドがある理由です。集約のように、無関係なコードを介して実装されている場合でも、同様のタイプの動作をグループ化するクラスを持つことを意図しています。または、同じ動作をサポートしようとしていますが、詳細に応じて代替の実装があります。これは、継承/オーバーロード タイプのソリューションのヒントになります。

問題は、このクラスが成長し続けるかどうか、そしてどのような方向に進むかです。2 つのメソッドは違いはありませんが、これが 3 つ以上繰り返される場合は、それをファサード/アダプターとして宣言するか、バリエーションの子クラスを作成する必要があるかを決定する必要があります。

あなたの疑いは正しいですが、においは燃える燃えさしからの煙のほんの一部です。万が一燃え上がった場合に備えて監視する必要があり、制御不能になる前に火を消す方法を決定する必要があります。

于 2009-07-14T14:23:37.947 に答える
0

私には過負荷のように見えます。あなたは何かをしようとしていますが、それを行うには 2 つの方法があります。いずれかの方法です。SomeClass レベルでは、作業を行うための 1 つの依存関係があり、その単一の依存クラスが同じことを行うための 2 つ (またはそれ以上) の方法をサポートするようにします。おそらく、相互に排他的な入力パラメーターを使用します。つまり、SomeClass のコードは同じですが、代わりに SomeWork として定義し、他の無関係なコードは含めません。

HTH

于 2009-07-13T16:20:24.350 に答える