У меня есть три класса, которые циклически зависят друг от друга:
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 */
}
Пример файла xml, который будет сгенерирован в случае сценария, содержащего два теста:
<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))
Ответы:
Технически, вы можете разрешить любую циклическую зависимость, используя интерфейсы, как показано в других ответах. Тем не менее, я рекомендую переосмыслить ваш дизайн. Я думаю, что не исключено, что вы сможете полностью избежать необходимости в дополнительных интерфейсах, в то время как ваш дизайн станет еще проще.
Я думаю, что нет необходимости
ReportGenerator
зависеть отTestScenario
напрямую.TestScenario
Похоже, у него есть две обязанности: он используется для выполнения теста и работает также как контейнер для результатов. Это нарушение ПСП. Интересно, что устраняя это нарушение, вы избавитесь и от циклической зависимости.Поэтому вместо того, чтобы позволить генератору отчетов получать данные из тестового сценария, передайте данные явно, используя некоторый объект значения. Это означает, заменить
по какому-то коду
Метод
getReportData
должен иметь тип возвращаемого значения, напримерReportData
, объект значения, который работает в качестве контейнера для данных, отображаемых в отчете.insertDataToDisplay
это метод, который ожидает объект именно этого типа.Таким образом,
ReportGenerator
иTestScenario
оба будут зависеть от тогоReportData
, что больше ни от чего не зависит, и первые два класса больше не зависят друг от друга.В качестве второго подхода: устранить нарушение SRP, пусть
TestScenario
будет ответственным за хранение результатов выполнения теста, но не за вызов исполнителя теста. Подумайте о реорганизации кода, чтобы не тестовый сценарий обращался к исполнителю теста, а выполнял тест снаружи и записывал результаты обратно вTestScenario
объект. В примере, который вы показали нам, это станет возможным, сделав доступLinkedList<Test>
внутрьTestScenario
public и переместивexecute
метод откуда-TestScenario
то еще, может быть, непосредственно вTestExecuter
, может быть, в новый классTestScenarioExecuter
.Таким образом,
TestExecuter
будет зависеть отTestScenario
иReportGenerator
,ReportGenerator
будет зависеть от тогоTestScenario
, тоже, ноTestScenario
будет зависеть от ничего.И, наконец, третий подход:
TestExecuter
слишком много обязанностей тоже. Он отвечает за выполнение тестов, а также за предоставлениеTestScenario
aReportGenerator
. Поместите эти две обязанности в два отдельных класса, и ваша циклическая зависимость снова исчезнет.Может быть больше вариантов для решения вашей проблемы, но я надеюсь, что вы поймете общую идею: вашей основной проблемой являются классы со слишком большим количеством обязанностей . Решите эту проблему, и вы автоматически избавитесь от циклической зависимости.
источник
ReportData
? Вы можете отредактировать свой вопрос и объяснить немного более подробно, что происходит внутриsaveReport
.interfaces
.Используя интерфейсы, вы можете решить круговую зависимость.
Текущий дизайн:
Предлагаемый дизайн:
В предлагаемом проекте конкретные классы не зависят от других конкретных классов, а только от абстракций (интерфейсов).
Важный:
Вы должны использовать шаблон творчества по вашему выбору (возможно, фабрику), чтобы избежать
new
выполнения каких-либо конкретных классов внутри любого другого конкретного класса или вызоваgetInstance()
. Только фабрика будет зависеть от конкретных классов. ВашMain
класс может служить фабрикой, если вы думаете, что отдельная фабрика будет излишней. Например, вы можете ввестиReportGenerator
вTestExecuter
вместо вызоваgetInstance()
илиnew
.источник
Поскольку
TestExecutor
используется толькоReportGenerator
внутри, вы должны иметь возможность определить интерфейс для него и обратиться к интерфейсу вTestScenario
. ТогдаTestExecutor
зависит отReportGenerator
,ReportGenerator
зависитTestScenario
иTestScenario
зависит от тогоITestExecutor
, что ни от чего не зависит.В идеале вы должны определять интерфейсы для всех ваших классов и выражать через них зависимости, но это наименьшее изменение, которое решит вашу проблему.
источник