Mam trzy klasy, które są od siebie zależne od siebie:
TestExecuter wykonuje żądania TestScenario i zapisuje plik raportu za pomocą klasy ReportGenerator. Więc:
- TestExecuter zależy od ReportGenerator do wygenerowania raportu
- ReportGenerator zależy od TestScenario i parametrów ustawionych z TestExecuter.
- TestScenario zależy od TestExecuter.
Nie mogę dowiedzieć się, jak usunąć te zależności.
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()
}
}
EDYCJA: w odpowiedzi na odpowiedź, więcej szczegółów na temat mojej klasy 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 */
}
Przykład pliku xml, który ma zostać wygenerowany w przypadku scenariusza zawierającego dwa testy:
<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))
Odpowiedzi:
Technicznie można rozwiązać dowolną zależność cykliczną za pomocą interfejsów, jak pokazano w innych odpowiedziach. Polecam jednak przemyśleć swój projekt. Myślę, że nie jest wykluczone, że można całkowicie uniknąć potrzeby stosowania dodatkowych interfejsów, a projekt staje się jeszcze prostszy.
Myślę, że nie jest konieczne,
ReportGenerator
aby polegaćTestScenario
bezpośrednio na.TestScenario
Wydaje się, że ma dwa elementy odpowiedzialne: służy do wykonywania testów i działa również jako pojemnik na wyniki. Jest to naruszenie SRP. Co ciekawe, rozwiązując to naruszenie, pozbędziesz się również cyklicznej zależności.Zamiast więc pozwolić generatorowi raportów pobrać dane ze scenariusza testowego, przekaż dane jawnie, używając obiektu wartości. To znaczy, zamień
przez jakiś kod jak
Metoda
getReportData
musi mieć typ zwracany, taki jakReportData
obiekt wartości, który działa jako kontener danych wyświetlanych w raporcie.insertDataToDisplay
jest metodą, która oczekuje obiektu dokładnie tego typu.W ten sposób,
ReportGenerator
iTestScenario
obie będą zależećReportData
, co nie zależy od niczego innego, a pierwsze dwie klasy już od siebie nie zależą.Jako drugie podejście: aby rozwiązać naruszenie zasad SRP,
TestScenario
ponosimy odpowiedzialność za przechowywanie wyników wykonania testu, ale nie za wywoływanie testera. Rozważ reorganizację kodu, aby scenariusz testowy nie uzyskiwał dostępu do testera, ale tester jest uruchamiany z zewnątrz i zapisuje wyniki z powrotem wTestScenario
obiekcie. W przykładzie, który pokazałeś nam, będzie to możliwe poprzez udostępnienie dostępu doLinkedList<Test>
wnętrzaTestScenario
publiczności i przeniesienieexecute
metody zTestScenario
innego miejsca, być może bezpośrednio do, aTestExecuter
może do nowej klasyTestScenarioExecuter
.W ten sposób,
TestExecuter
będzie zależeć odTestScenario
aReportGenerator
,ReportGenerator
będzie zależećTestScenario
też, aleTestScenario
będzie zależeć od niczego innego.I wreszcie trzecie podejście:
TestExecuter
ma też zbyt wiele obowiązków. Jest odpowiedzialny za wykonywanie testów, a także za dostarczenieTestScenario
doReportGenerator
. Podziel te dwie obowiązki na dwie osobne klasy, a twoja cykliczna zależność ponownie zniknie.Może być więcej wariantów podejścia do twojego problemu, ale mam nadzieję, że masz ogólny pomysł: twoim głównym problemem są klasy ze zbyt wieloma obowiązkami . Rozwiąż ten problem, a automatycznie pozbędziesz się cyklicznej zależności.
źródło
ReportData
? Możesz rozważyć edycję swojego pytania i wyjaśnić nieco bardziej szczegółowo, co dzieje się wewnątrzsaveReport
.interfaces
.Za pomocą interfejsów można rozwiązać zależność cykliczną.
Obecny projekt:
Proponowany projekt:
W proponowanym projekcie konkretne klasy nie zależą od innych konkretnych klas, ale tylko od abstrakcji (interfejsów).
Ważny:
Musisz użyć wybranego przez siebie wzoru kreacji (być może fabryki), aby uniknąć
new
wykonania jakichkolwiek konkretnych klas wewnątrz jakiejkolwiek innej konkretnej klasy lub powołaniagetInstance()
. Tylko fabryka będzie zależna od konkretnych klas. TwojaMain
klasa może służyć jako fabryka, jeśli uważasz, że dedykowana fabryka byłaby przesada. Na przykład można wstrzyknąćReportGenerator
doTestExecuter
zamiast dzwonićgetInstance()
lubnew
.źródło
Ponieważ
TestExecutor
używa tylkoReportGenerator
wewnętrznie, powinieneś być w stanie zdefiniować dla niego interfejs i zapoznać się z interfejsem wTestScenario
. NastępnieTestExecutor
zależy odReportGenerator
,ReportGenerator
zależyTestScenario
iTestScenario
zależy od tegoITestExecutor
, co nie zależy od niczego.Idealnie byłoby zdefiniować interfejsy dla wszystkich swoich klas i wyrażać za ich pośrednictwem zależności, ale jest to najmniejsza zmiana, która rozwiąże problem.
źródło