J'ai trois classes qui sont circulaires dépendantes les unes des autres:
TestExecuter exécute les demandes de TestScenario et enregistre un fichier de rapport à l'aide de la classe ReportGenerator. Alors:
- TestExecuter dépend de ReportGenerator pour générer le rapport
- ReportGenerator dépend de TestScenario et des paramètres définis par TestExecuter.
- TestScenario dépend de TestExecuter.
Impossible de comprendre comment supprimer ces dépendances.
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()
}
}
EDIT: en réponse à une réponse, plus de détails sur ma classe 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 */
}
Exemple de fichier XML à générer dans le cas d’un scénario contenant deux tests:
<testScenario name="scenario1">
<test name="test1">
<result>false</result>
</test>
<test name="test1">
<result>true</result>
</test>
</testScenario >
File(filename).write(Report); Report = XMLResult(ResultData).toString(); ResultData = TestSuite(SingleTestLogic).execute(TestDataIterator(TestDetailsList))
Réponses:
Techniquement, vous pouvez résoudre toute dépendance cyclique en utilisant des interfaces, comme indiqué dans les autres réponses. Cependant, je recommande de repenser votre conception. Je pense qu'il n'est pas improbable que vous puissiez éviter complètement le besoin d'interfaces supplémentaires, tandis que votre conception devient encore plus simple.
Je suppose qu’il n’est pas nécessaire que cela
ReportGenerator
dépendeTestScenario
directement d’ un .TestScenario
semble avoir deux responsabilités: il est utilisé pour l'exécution du test et fonctionne également comme un conteneur pour les résultats. Ceci est une violation du PÉR. Fait intéressant, en résolvant cette violation, vous vous débarrasserez également de la dépendance cyclique.Par conséquent, au lieu de laisser le générateur de rapports récupérer les données du scénario de test, transmettez-les explicitement à l'aide d'un objet de valeur. Cela signifie, remplace
par un code comme
La méthode
getReportData
doit avoir un type de retour commeReportData
, un objet valeur qui fonctionne comme un conteneur pour les données à afficher dans le rapport.insertDataToDisplay
est une méthode qui attend un objet de ce type.De cette façon,
ReportGenerator
etTestScenario
dépendra , toutReportData
, qui dépend de rien d' autre, et les deux premières classes ne dépendent pas de l'autre plus.Dans une deuxième approche: pour résoudre la violation SRP, laissez
TestScenario
la responsabilité de conserver les résultats d'une exécution de test, mais pas d'appeler l'exécuteur de test. Envisagez de réorganiser le code pour que le scénario de test n'accède pas à l'exécuteur de test, mais que l'exécuteur de test soit démarré de l'extérieur et enregistre les résultats dans l'TestScenario
objet. Dans l'exemple que vous nous avez montré, cela sera possible en rendant l'accès à l'LinkedList<Test>
intérieur duTestScenario
public et en déplaçant laexecute
méthode d'unTestScenario
endroit à un autre, peut-être directement dans uneTestExecuter
classe, peut-être dans une nouvelle classeTestScenarioExecuter
.De cette façon,
TestExecuter
dépendraTestScenario
etReportGenerator
,ReportGenerator
dépendraTestScenario
aussi, maisTestScenario
dépendra de rien d' autre.Et enfin, une troisième approche:
TestExecuter
trop de responsabilités. Il est responsable de l'exécution des tests ainsi que de la fournitureTestScenario
d'unReportGenerator
. Mettez ces deux responsabilités en deux classes distinctes et votre dépendance cyclique disparaîtra à nouveau.Il y a peut-être plus de variantes pour aborder votre problème, mais j'espère que vous aurez une idée générale: votre problème central est constitué de classes comportant trop de responsabilités . Résolvez ce problème et vous vous débarrasserez automatiquement de la dépendance cyclique.
la source
ReportData
? Vous pouvez envisager de modifier votre question et d'expliquer un peu plus en détail ce qui se passe à l'intérieur desaveReport
.interfaces
.En utilisant des interfaces, vous pouvez résoudre la dépendance circulaire.
Conception actuelle:
Conception proposée:
Dans la conception proposée, les classes concrètes ne dépendent pas d’autres classes concrètes mais seulement d’abstractions (interfaces).
Important:
Vous devez utiliser le modèle de création de votre choix (peut-être une usine) pour éviter de définir
new
des classes concrètes dans des classes ou des appels concretsgetInstance()
. Seule l'usine aura des dépendances sur des classes concrètes. VotreMain
classe pourrait servir d’usine si vous pensez qu’une usine dédiée serait exagérée. Par exemple, vous pouvez injecter unReportGenerator
enTestExecuter
au lieu d'appelergetInstance()
ounew
.la source
Etant donné
TestExecutor
que n'utilise qu'enReportGenerator
interne, vous devriez pouvoir définir une interface pour cette interface et vous reporter à l'interface dansTestScenario
. CelaTestExecutor
dépendReportGenerator
,ReportGenerator
dépendTestScenario
, etTestScenario
dépendITestExecutor
, qui ne dépend de rien.Dans l’idéal, vous définissez des interfaces pour toutes vos classes et exprimez des dépendances à travers elles, mais c’est le plus petit changement qui résoudra votre problème.
la source