Tengo tres clases que son circulares dependientes entre sí:
TestExecuter ejecuta solicitudes de TestScenario y guarda un archivo de informe usando la clase ReportGenerator. Asi que:
- TestExecuter depende de ReportGenerator para generar el informe
- ReportGenerator depende de TestScenario y de los parámetros establecidos desde TestExecuter.
- TestScenario depende de TestExecuter.
No puedo entender cómo eliminar estas dependencias.
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()
}
}
EDITAR: en respuesta a una respuesta, más detalles sobre mi clase 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 */
}
Un ejemplo del archivo xml que se generará en caso de un escenario que contenga dos pruebas:
<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))Respuestas:
Técnicamente, puede resolver cualquier dependencia cíclica mediante el uso de interfaces, como se muestra en las otras respuestas. Sin embargo, recomiendo repensar su diseño. Creo que no es improbable que pueda evitar la necesidad de interfaces adicionales por completo, mientras que su diseño se vuelve aún más simple.
Supongo que no es necesario que un
ReportGeneratordependaTestScenariodirectamente de un .TestScenarioparece tener dos responsabilidades: se usa para la ejecución de la prueba y también funciona como un contenedor para los resultados. Esto es una violación del SRP. Curiosamente, al resolver esa violación, también se librará de la dependencia cíclica.Entonces, en lugar de permitir que el generador de informes tome datos del escenario de prueba, pase los datos explícitamente utilizando algún objeto de valor. Eso significa, reemplazar
por algún código como
El método
getReportDatadebe tener un tipo de retorno comoReportData, un objeto de valor que funciona como un contenedor para los datos que se mostrarán en el informe.insertDataToDisplayes un método que espera un objeto exactamente de ese tipo.De esta manera,
ReportGeneratoryTestScenarioambos dependeránReportData, lo que no depende de nada más, y las dos primeras clases ya no dependen entre sí.Como segundo enfoque: para resolver la violación de SRP, seamos
TestScenarioresponsables de mantener los resultados de la ejecución de una prueba, pero no de llamar al ejecutor de la prueba. Considere reorganizar el código para que el escenario de prueba no acceda al ejecutante de prueba, pero el ejecutante de prueba se inicia desde el exterior y escribe los resultados nuevamente en elTestScenarioobjeto. En el ejemplo que nos mostró, eso será posible haciendo que el acceso alLinkedList<Test>interior delTestScenariopúblico, y moviendo elexecutemétodo deTestScenariootro lugar, tal vez directamente a unaTestExecuter, tal vez a una nueva claseTestScenarioExecuter.De esa manera,
TestExecuterdependeráTestScenarioyReportGenerator,ReportGeneratordependeráTestScenario, también, peroTestScenariodependerá de nada más.Y finalmente, un tercer enfoque:
TestExecutertambién tiene demasiadas responsabilidades. Es responsable de ejecutar pruebas y de proporcionar aTestScenarioa aReportGenerator. Ponga estas dos responsabilidades en dos clases separadas, y su dependencia cíclica se desvanecerá nuevamente.Puede haber más variantes para abordar su problema, pero espero que comprenda la idea general: su problema principal son las clases con demasiadas responsabilidades . Resuelva ese problema y se librará de la dependencia cíclica automáticamente.
fuente
ReportData? Puede considerar editar su pregunta y explicar un poco más detallado lo que sucede dentro desaveReport.interfaces.Mediante el uso de interfaces, puede resolver la dependencia circular.
Diseño actual:
Diseño propuesto:
En el diseño propuesto, las clases concretas no dependen de otras clases concretas sino solo de abstracciones (interfaces).
Importante:
Debe usar el patrón de creación que elija (tal vez una fábrica) para evitar la ejecución
newde cualquier clase concreta dentro de cualquier otra clase concreta o llamadagetInstance(). Solo la fábrica tendrá dependencias de clases concretas. SuMainclase podría servir como fábrica si cree que una fábrica dedicada sería exagerada. Por ejemplo, puede inyectar unReportGeneratorenTestExecuterlugar de llamar agetInstance()onew.fuente
Como
TestExecutorsolo se usaReportGeneratorinternamente, debe poder definir una interfaz para ella y consultar la interfaz enTestScenario. LuegoTestExecutordependeReportGenerator,ReportGeneratordependeTestScenarioyTestScenariodepende deITestExecutor, lo que no depende de nada.Lo ideal sería definir interfaces para todas sus clases y expresar dependencias a través de ellas, pero este es el cambio más pequeño que resolverá su problema.
fuente