循環依存関係を解決する方法は?


33

相互に循環依存する3つのクラスがあります。

TestExecuterはTestScenarioのリクエストを実行し、ReportGeneratorクラスを使用してレポートファイルを保存します。そう:

  • TestExecuterはReportGeneratorに依存してレポートを生成します
  • ReportGeneratorは、TestScenarioおよびTestExecuterから設定されたパラメーターに依存します。
  • TestScenarioはTestExecuterに依存しています。

それらの依存関係を削除する方法がわかりません。

public class TestExecuter {

  ReportGenerator reportGenerator;  

  public void getReportGenerator() {
     reportGenerator = ReportGenerator.getInstance();
     reportGenerator.setParams(this.params);
     /* this.params several parameters from TestExecuter class example this.owner */
  }

  public void setTestScenario (TestScenario  ts) {
     reportGenerator.setTestScenario(ts); 
  }

  public void saveReport() {
     reportGenerator.saveReport();    
  }

  public void executeRequest() {
    /* do things */
  }
}
public class ReportGenerator{
    public static ReportGenerator getInstance(){}
    public void setParams(String params){}
    public void setTestScenario (TestScenario ts){}
    public void saveReport(){}
}
public class TestScenario {

    TestExecuter testExecuter;

    public TestScenario(TestExecuter te) {
        this.testExecuter=te;
    }

    public void execute() {
        testExecuter.executeRequest();
    }
}
public class Main {
    public static void main(String [] args) {
      TestExecuter te = new TestExecuter();
      TestScenario ts = new TestScenario(te);

      ts.execute();
      te.getReportGenerator();
      te.setTestScenario(ts);
      te.saveReport()
    }
}

編集:答えに応じて、TestScenarioクラスの詳細:

public class TestScenario {
    private LinkedList<Test> testList;
    TestExecuter testExecuter;

    public TestScenario(TestExecuter te) {
        this.testExecuter=te;
    }

    public void execute() {
        for (Test test: testList) {
            testExecuter.executeRequest(test); 
        }
    }
}

public class Test {
  private String testName;
  private String testResult;
}

public class ReportData {
/*shall have all information of the TestScenario including the list of Test */
    }

2つのテストを含むシナリオの場合に生成されるxmlファイルの例:

<testScenario name="scenario1">
   <test name="test1">
     <result>false</result>
   </test>
   <test name="test1">
     <result>true</result>
   </test>
</testScenario >

あなたのオブジェクトが求めて逆方向に行くの識別試してみてくださいあなたが仕事に以前の1のために必要です(オブジェクト) -例えば:File(filename).write(Report); Report = XMLResult(ResultData).toString(); ResultData = TestSuite(SingleTestLogic).execute(TestDataIterator(TestDetailsList))
身震い

回答:


35

技術的には、他の回答に示されているように、インターフェイスを使用して循環依存関係を解決できます。ただし、設計を再考することをお勧めします。設計がさらにシンプルになる一方で、追加のインターフェイスの必要性を完全に回避できる可能性は低いと思います。

に直接ReportGenerator依存する必要はないと思いTestScenarioます。TestScenario2つの責任があるようです:テストの実行に使用され、結果のコンテナとしても機能します。これはSRPの違反です。興味深いことに、その違反を解決することで、循環依存関係も取り除くことができます。

そのため、レポートジェネレーターにテストシナリオからデータを取得させる代わりに、値オブジェクトを使用してデータを明示的に渡します。つまり、置き換える

   reportGenerator.setTestScenario(ts); 

のようないくつかのコードによって

reportGenerator.insertDataToDisplay(ts.getReportData()); 

このメソッドには、レポートに表示されるデータのコンテナとして機能する値オブジェクトのgetReportDataような戻りReportData値の型が必要です。insertDataToDisplayまさにそのタイプのオブジェクトを期待するメソッドです。

この方法でReportGeneratorTestScenario両方に依存しますReportData。これは何にも依存せず、最初の2つのクラスは互いに依存しなくなります。

2番目のアプローチとして:SRP違反を解決するにTestScenarioは、テスト実行の結果を保持するようにしますが、テスト実行者を呼び出すことはしません。テストシナリオがテスト実行者にアクセスしないようにコードを再編成することを検討してください。ただし、テスト実行者は外部から開始され、結果をTestScenarioオブジェクトに書き戻します。例では、アクセスすることによって可能になることを、私たちに示したLinkedList<Test>の内部TestScenario、および移動することによって、公共のexecuteから方法をTestScenario、多分直接に他のどこかにTestExecuter、多分新しいクラスにTestScenarioExecuter

そうTestExecuterすれば、とに依存しTestScenarioReportGeneratorReportGeneratorも依存しTestScenarioますが、TestScenario他には何も依存しません。

最後に、3番目のアプローチ:TestExecuterあまりにも多くの責任があります。テストを実行するだけでなく、を提供する責任TestScenarioがありReportGeneratorます。これらの2つの責任を2つの別個のクラスに入れると、循環依存関係が再び消滅します。

あなたの問題にアプローチするためのより多くのバリアントがあるかもしれませんが、私はあなたが一般的なアイデアを得ることを願っています:あなたのコア問題はあまりにも多くの責任を持つクラスです。この問題を解決すると、循環依存関係が自動的に解消されます。


あなたの答えをありがとう、実際に私はTestScenarioのすべての情報が最後にレポートを生成できるようにする必要があります:(
sabrina2020

@ sabrina2020:そして、あなたがそのすべての情報を入れることを妨げるものは何ReportDataですか?あなたはあなたの質問を編集して、内部で起こることをもう少し詳細に説明することを考えるかもしれませんsaveReport
ドックブラウン

実際、私のTestScenarioにはテストのリストが含まれており、レポートXMLファイルにすべての情報が必要なので、この場合はReportDataにすべてが含まれます。詳細については回答を編集します。
sabrina2020

1
+1:あなたは私にいたinterfaces
ジョエルイーサトン16年

@ sabrina2020:私は私の答えに2つの異なるアプローチを追加しました。あなたのニーズに最も合ったものを選びます。
ドックブラウン

8

インターフェイスを使用すると、循環依存関係を解決できます。

現在の設計:

ここに画像の説明を入力してください

提案された設計:

ここに画像の説明を入力してください

提案された設計では、具象クラスは他の具象クラスに依存せず、抽象化(インターフェース)のみに依存します。

重要:

他の具象クラス内または呼び出し元の具象クラスが実行されないようにするには、選択した作成パターン(おそらくファクトリー)を使用する必要があります。ファクトリのみが具象クラスに依存します。あなた専用の工場はやり過ぎだと思う場合クラスは、工場としての役割を果たすことができました。たとえば、あなたは、注入することができへの代わりに呼び出すのか。newgetInstance()MainReportGeneratorTestExecutergetInstance()new


3

以来TestExecutorのみ使用しReportGenerator、内部で、あなたはそれのためのインタフェースを定義することができ、かつにおけるインタフェースを参照してくださいTestScenario。次に、にTestExecutor依存しReportGenerator、にReportGenerator依存しTestScenario、にTestScenario依存しますがITestExecutor、これは何にも依存しません。

理想的には、すべてのクラスのインターフェースを定義し、それらを介して依存関係を表現しますが、これは問題を解決する最小の変更です。

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