2009-08-12 3 views
7

私は貧血ドメインモデルを持つレガシーシステムで作業しています。レガシーシステムのリポジトリにアクセスするリファクタリングドメインロジック

このドメインのエンティティクラスは、Car,CarTypeCarComponentCarComponentTypeです。

それぞれについて、別個のリポジトリがあります。これらのリポジトリにアクセスし、基本的にすべてのロジックを含む多くのサービスもあります。

ベンダーがCarComponentTypeを廃止できるかどうかを判断する方法を実装する必要があります。そのロジックは次の通りです。今日、そのコンポーネントを持つ既存の車がない場合に限り、コンポーネントを中断することができます。

最初は、これをサービスクラスで実装しました。

public boolean canBeDiscontinued(CarComponentType carComponentType) { 
    List<Car> cars = carRepository.getCarsWithComponent(carComponentType); 
    return cars.isEmpty(); 
} 

これは機能しますが、このロジックはコードの他の場所から使用されます。それは成長かもしれないが、それは代わりに内部CarComponentTypeクラスを合うことができる何かのようになります。

public boolean canBeDiscontinued() { 
    List<Car> cars = carRepository.getCarsWithComponent(this); 
    return cars.isEmpty(); 
} 

しかし、それはリポジトリにアクセスする必要があるので、私は、そこにそれを置くことができない(と私はそれを理解してエンティティがデータアクセス層を認識するための非常に深刻な反パターンです)。コンポーネントタイプをロードすると、そのタイプのカーはすべてロードできません。何千ものオブジェクトになる可能性があるからです。私たちはORMを使用していないので、かさばるだけでなくエラーが起こりやすいために、遅延ロードされたコレクションを作成します。

私が最初にやったように、サービスクラスで実際にこのメソッドを使用する方が適切ですか?それは重要ではないですか?別の選択肢がありますか?別の出発点からリファクタリングを開始する必要がありますか?

同様の質問hereがあります。しかし、私の質問はJavaに関連しているので、私の解決策は私の場合は当てはまりません。また、私のドメインモデルとして自動車やコンポーネントを使用することについては、事前に申し訳ありません。おそらく、少し短いものの:)

答えて

3
+0

スペックの実装はどのレイヤーですか?インフラ? – Chris

+0

「ドメイン概念」が仕様に実装されているため、仕様はドメイン層の不可欠な部分です。 –

5

フレデリックGheyselsの答えのために良い候補のように聞こえるが、良いです。詳述すると:あなたのケースでは、あなた仕様のインターフェースをdefininigによって開始することができます(私のC#構文を言い訳):

public interface ICarSpecification 
{ 
    bool IsSatisfiedBy(CarComponentType carComponentType); 
} 

次に、あなたのリポジトリを使用していますICarSpecificationのimplmenetationを作成することができます。

あなたはすぐそこに止めることができますが、私は特に仕様パターンについて気に入らないことはそれほど発見できないということです。一つの可能​​な解決策はCarComponentType自体に仕様を注入することです:あなたは、クラスのすべてのインスタンスで仕様を持ち歩くのは好きではない場合、

public class CarComponentType 
{ 
    private readonly ICarSpecification discontinueSpec; 

    public CarComponentType(ICarSpecification discontinueSpec) 
    { 
     this.discontinueSpec = discontinueSpec; 
    } 

    public bool CanBeDiscontinued() 
    { 
     return this.discontinueSpec.IsSatisfiedBy(this); 
    } 
} 

また、あなたの代わりにコンストラクタ・インジェクションのメソッド・インジェクションを使用することができますこのような方法は実際には実装上の価値を付加するものではなく、より発見可能である。

+0

ご清聴ありがとうございます。私が組み合わせることができるより多くの仕様があれば、これは適切と思われます。私の場合は、わかりません。リポジトリを各エンティティに注入する代わりに、*リポジトリを使用する*仕様を注入します。それは本当にはるかに優れていますか? – waxwing

+2

まあ、それはリポジトリからクラスを分離し、それはおそらくあなたがテストのためにやりたい仕様の実装に渡すことによって、ユニットテストに簡単です。 –

+0

うん:chriskes何今言った:)真剣に、それがまたはリポジトリに依存しない場合があります仕様ちょうど別の戦略を、作ります。それでも、私はあなたが実際に仕様に普遍的な依存関係を持つことを好まない場合に備えて、メソッド注入オプションを含めました。 –

1

私は次の男ほど貧血ドメインモデルが嫌いだと言っても過言ではないと思います。

貧血ドメインモデル/サービス(反)パターンを既に確立しているシステムでは、私があなたがここにいると信じているので、別のパターンを導入すると、システムを阻止することができます。そのような決定はチームによってなされるべきであり、明確な利益をもたらすべきである。

また、元のコードスニペットは、他の回答で提案されている解決策(Mark and Frederik、ちょうど観測:-)に比べて簡単だと思うし、より複雑な解決法は実際には何の利益ももたらさない - 私が意味する、機能はどちらの場合も同じですが、後には、より多くの可動部品を使用しています。

進歩する方法に関しては、一例を挙げて言い難い。それは場所のレビューでいたら、それは、その後、あなたのサービスクラスにコードを減らす必要があり、私はそこに開始するように誘惑されると思いますので、明確な利点を持っていると同じように(あなたが現在使用されていません言及した)ORMを導入することに行くための一つの方法かもしれません状況。

+0

ありがとうございます。私はこの答えに自分自身をほとんど辞任しましたが、私は学問的な理由で不思議に思っていました。私はそこにいると感じています*私が見ていないよりスマートな解決策にすべきです。 – waxwing

3

"これは中止することができますか"は、これらのクラスのいずれにも属していないと思います。部品の製造を中止できるかどうかは誰が決定しますか?車や車の部品ではありません。私はあなたがサービスに実装された初期の方法で正しい道にいると思います。あなたがそのようなあなたの「canBeDiscontinued」などの在庫関連の質問を依頼する必要があり、コードの複数の場所を持っている場合、それが意味をなすかもしれない

carsUsingComponent(CarComponent comp) 
canComponentBeDiscontinued(CarComponent comp) 
etc 

:おそらく、あなたは次のように車の在庫品目についての質問に答えるための責任だCarInventoryManagementServiceが必要その責任を持ってサービスを創造することです。

+0

これは少し主観的です。ドメインオブジェクトがクライアントによってどのように使用されているかを「認識」しなければならないかどうかは、境界線の場合よりもしばしばです。この場合はおそらくあなたが正しいでしょう。しかし、CarComponentTypeに間違いなく適合するが、オブジェクト自体に含まれていないデータが必要な別の関数だとしましょう。それが私がもっと興味深いです。 – waxwing

+0

私は責任主義設計を考えています。それはまだ生産されているかどうか、または自動車の作成者であるかどうかを判断する役割を担うのは、Carですか?車は誰がそれを生産しているのか確かに知っているかもしれませんが、それはすべての車種が終わったかどうかについて決定を下す責任がありません。ドメインオブジェクトは一般的に、自分自身に関する質問に答えるだけです。ドメインオブジェクトのすべてのタイプに適用される質問は、通常、ドメインオブジェクトサービスの責任です。私は明らかにこのソフトウェアを知らないが、それは一般的な原則である。 –

関連する問題