互いに循環依存している3つのクラスがあります。
TestExecuterはTestScenarioのリクエストを実行し、ReportGeneratorクラスを使用してレポートファイルを保存します。そう:
これらの依存関係を削除する方法を理解できません。
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 >
技術的には、他の回答に示されているように、インターフェースを使用して循環依存関係を解決できます。ただし、デザインを再考することをお勧めします。あなたができる可能性は低いとは思いませんavoid追加のインターフェースが完全に必要である一方で、設計はさらに単純になります。
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>
へのアクセスを作成し、execute
メソッドをTestScenario
からどこか別の場所で、おそらくTestExecuter
に直接、おそらく新しいクラスTestScenarioExecuter
に。
このように、TestExecuter
はTestScenario
とReportGenerator
に依存し、ReportGenerator
もTestScenario
に依存しますが、TestScenario
は何にも依存しません。
そして最後に、3番目のアプローチ:TestExecuter
にも責任が多すぎます。これは、テストの実行とTestScenario
へのReportGenerator
の提供を担当します。これらの2つの責任を2つの別々のクラスに入れると、循環依存関係が再び消えます。
あなたの問題に取り組むためのより多くのバリアントがあるかもしれませんが、私はあなたが一般的な考えを得るのを望みます:あなたのコアの問題は多すぎる責任のクラスです。その問題を解決すると、循環依存関係が自動的に解消されます。
インターフェイスを使用することで、循環依存関係を解決できます。
現在のデザイン:
提案された設計:
提案された設計では、具象クラスは他の具象クラスに依存せず、抽象化(インターフェース)にのみ依存します。
重要:
他のコンクリート内のコンクリートクラスのnew
を実行しないように、選択した作成パターンを使用する必要があります(おそらくファクトリ)。クラスまたは呼び出しgetInstance()
。ファクトリだけが具象クラスに依存します。専用ファクトリーではやり過ぎだと思われる場合は、Main
クラスをファクトリーとして使用できます。たとえば、getInstance()
またはReportGenerator
を呼び出す代わりに、TestExecuter
をnew
に注入できます。
TestExecutor
は内部でReportGenerator
のみを使用するため、そのためのインターフェースを定義し、TestScenario
のインターフェースを参照できるようにする必要があります。次に、TestExecutor
はReportGenerator
に依存し、ReportGenerator
はTestScenario
に依存し、TestScenario
はITestExecutor
に依存します。 t何かに依存しています。
すべてのクラスのインターフェースを定義し、それらを介して依存関係を表現するのが理想的ですが、これが問題を解決するための最小の変更です。