循環依存を解決する方法は?
On 1月 1, 2021 by admin相互に循環依存する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 >
コメント
回答
技術的には、他の回答に示されているように、インターフェイスを使用して循環依存を解決できます。しかし、私はあなたのデザインを再考することをお勧めします。 追加のインターフェースの必要性を完全に回避しながら、設計をさらにシンプルにすることができる可能性は低いと思います。
ReportGenerator
がTestScenario
に直接依存する必要はないと思います。 TestScenario
には、2つの責任があるようです。テストの実行に使用されることと、結果のコンテナとしても機能することです。これはSRPの違反です。興味深いことに、その違反を解決することで、循環依存関係も取り除くことができます。
したがって、レポートジェネレーターにテストシナリオからデータを取得させる代わりに、値オブジェクトを使用してデータを明示的に渡します。つまり、
reportGenerator.setTestScenario(ts);
を次のようなコードに置き換えます
reportGenerator.insertDataToDisplay(ts.getReportData());
メソッドgetReportData
には、レポートに表示されるデータのコンテナとして機能する値オブジェクトであるReportData
のような戻り値の型が必要です。 insertDataToDisplay
は、まさにそのタイプのオブジェクトを期待するメソッドです。
このように、ReportGenerator
とTestScenario
は両方ともReportData
に依存しますが、これは他には何も依存せず、最初の2つのクラスは相互に依存しなくなります。
2番目のアプローチとして:SRP違反を解決するには、TestScenario
がテスト実行の結果を保持する責任を負いますが、テスト実行者を呼び出す責任はありません。テストシナリオがテスト実行者にアクセスしないようにコードを再編成することを検討してください。ただし、テスト実行者は外部から開始され、結果をTestScenario
オブジェクトに書き戻します。あなたが示した例では、TestScenario
内のLinkedList<Test>
へのアクセスを公開し、
メソッドからTestScenario
から別の場所へ、おそらく直接TestExecuter
へ、おそらく新しいクラスへTestScenarioExecuter
。
このように、TestExecuter
はTestScenario
に依存しますReportGenerator
、ReportGenerator
もTestScenario
に依存しますが、TestScenario
は他に依存しません。
そして最後に、3番目のアプローチ:TestExecuter
にも多くの責任があります。テストの実行と、ReportGenerator
へのTestScenario
の提供を担当します。これらの2つの責任を2つの別々のクラスに入れると、循環依存関係は再び消滅します。
問題に取り組むバリエーションは他にもあるかもしれませんが、一般的な考え方を理解していただければ幸いです。コアの問題は責任が多すぎます。その問題を解決すると、循環依存関係が自動的に解消されます。
コメント
- ご回答ありがとうございます。実際、TestScenarioのすべての情報が必要です。最後に私のレポートを生成できるようにするには:(
- @ sabrina2020:そしてそのすべての情報を
ReportData
に入れるのを妨げるものは何ですか?質問を編集して、saveReport
内で何が起こっているかをもう少し詳しく説明することを検討してください。 - 実際、私のTestScenarioにはテストのリストが含まれているので、すべてが必要です。レポートのxmlファイルに情報が含まれているため、この場合はReportDataにすべてが含まれます。詳細については、回答を編集します。ありがとうございます。
- +1:
interfaces
。 - @ sabrina2020:2つの異なるアプローチを回答に追加しました。ニーズに最も適したものを選択してください。
回答
インターフェースを使用することで、循環依存関係を解決できます。
現在の設計:
提案されたデザイン:
提案されたデザインコンクリートクラスは他の具象クラスに依存せず、抽象化(インターフェース)にのみ依存します。
重要:
実行を回避するには、選択した作成パターン(おそらく工場)を使用する必要があります<他の具象クラス内の具象クラスのdivid = "f465b4b90a">
、またはgetInstance()
の呼び出し。ファクトリのみが具象クラスに依存します。専用のファクトリがやり過ぎだと思われる場合は、Main
クラスがファクトリとして機能する可能性があります。たとえば、getInstance()
またはividを呼び出す代わりに、ReportGenerator
をTestExecuter
に挿入できます。 = “f465b4b90a”>
。
回答
TestExecutor
以降内部でのみReportGenerator
を使用します。そのためのインターフェースを定義し、TestScenario
でインターフェースを参照できるはずです。次に、TestExecutor
はReportGenerator
に依存し、ReportGenerator
はTestScenario
、およびTestScenario
はITestExecutor
に依存しますが、これは何にも依存しません。
理想的にはあなた「すべてのクラスのインターフェースを定義し、それらを介して依存関係を表現する必要がありますが、これは問題を解決する最小の変更です。
File(filename).write(Report); Report = XMLResult(ResultData).toString(); ResultData = TestSuite(SingleTestLogic).execute(TestDataIterator(TestDetailsList))