Hogyan lehet megoldani a körfüggőséget?
On január 1, 2021 by adminHárom osztályom van, amelyek körkörösen függenek egymástól:
A TestExecuter végrehajtja a TestScenario kéréseit, és egy jelentésfájlt ment a ReportGenerator osztály használatával. . Tehát:
- A TestExecuter a ReportGeneratortól függ a jelentés létrehozásához
- A ReportGenerator a TestScenario-tól és a TestExecuter által beállított paraméterektől függ.
- TestScenario a TestExecuter függvénye.
Nem lehet kitalálni, hogyan lehet eltávolítani a függőségeket.
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() } }
SZERKESZTÉS: válaszként válasz, további részletek a TestScenario osztályomról:
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 */ }
Példa a Két tesztet tartalmazó forgatókönyv esetén létrehozandó xml fájl:
<testScenario name="scenario1"> <test name="test1"> <result>false</result> </test> <test name="test1"> <result>true</result> </test> </testScenario >
Megjegyzések
Válasz
Technikailag bármilyen ciklikus függőség megoldható interfészek használatával, amint az a többi válaszban is szerepel. Javaslom azonban a tervezés újragondolását. Azt hiszem, nem valószínű, hogy elkerülheti a további interfészek szükségességét teljesen, miközben a tervezése még egyszerűbbé válik.
Azt hiszem, nem szükséges, hogy egy ReportGenerator
közvetlenül egy TestScenario
-től függjön. Úgy tűnik, hogy a TestScenario
két felelősséggel rendelkezik: teszt végrehajtására használják, és az eredmények tárolására is szolgál. Ez az SRP megsértése. Érdekes módon a szabálysértés megoldásával megszabadul a ciklikus függőségtől is.
Tehát ahelyett, hogy hagyná, hogy a jelentésgenerátor megragadja az adatokat a teszt forgatókönyvéből, adja át az adatokat kifejezetten valamilyen értékobjektum használatával. Ez azt jelenti, hogy cserélje ki a
reportGenerator.setTestScenario(ts);
kódot, például
reportGenerator.insertDataToDisplay(ts.getReportData());
A metódust getReportData
visszatérési típussal kell rendelkeznie, például ReportData
, egy értékobjektum, amely konténerként működik a jelentésben megjelenítendő adatok számára. A insertDataToDisplay
olyan módszer, amely pontosan egy ilyen típusú objektumra számít.
Így ReportGenerator
és TestScenario
mindkettő ReportData
függ, ami nem mástól függ, és az első két osztály már nem függ egymástól.
Második megközelítésként: az SRP megsértésének kijavításáért TestScenario
legyen felelős a teszt végrehajtásának eredményeinek megőrzéséért, de ne a teszt végrehajtó meghívásáért. Fontolja meg a kód átszervezését, hogy ne a teszt forgatókönyv férjen hozzá a teszt végrehajtóhoz, hanem a teszt végrehajtó kívülről indul, és az eredményeket visszaírja a TestScenario
objektumba. A nekünk bemutatott példában ez úgy lehetséges, hogy nyilvánosvá teszi a LinkedList<Test>
hozzáférést a TestScenario
belsejében, és a execute
módszer TestScenario
-ből máshova, esetleg közvetlenül egy TestExecuter
-be, esetleg egy új osztályba TestScenarioExecuter
.
Így TestExecuter
a TestScenario
és ReportGenerator
, ReportGenerator
a TestScenario
-től is függ, de semmi mástól nem függ.
És végül egy harmadik megközelítés: TestExecuter
is túl sok felelősséggel tartozik. Feladata a tesztek végrehajtása, valamint a TestScenario
megadása egy ReportGenerator
számára. Tedd ezt a két felelősséget két külön osztályba, és a ciklikus függőséged ismét eltűnik.
Lehet, hogy több variáns van a probléma megközelítéséhez, de remélem, hogy megkapod az általános gondolatot: a fő problémád a túl sok felelősség . Oldja meg a problémát, és automatikusan megszabadul a ciklikus függőségtől.
Megjegyzések
- Köszönöm a válaszát, valójában minden információra szükségem van a TestScenario-ban hogy elkészíthessem a jelentésemet a végén 🙁
- @ sabrina2020: és mi akadályozza Önt abban, hogy ezeket az információkat a
ReportData
fájlba helyezze?Fontolja meg a kérdés szerkesztését, és egy kicsit részletesebb magyarázatot, hogy mi történik asaveReport
fájlban. - Valójában a TestScenario tartalmazza a Test listáját, és szeretnék mindent információk egy report xml fájlban, így ebben az esetben a ReportData rendelkezik mindennel, további részletekért szerkesztem a válaszomat, köszönöm!
- +1: Ön volt a
interfaces
. - @ sabrina2020: Két különböző megközelítést adtam a válaszomhoz, válaszd ki azt, amelyik az Ön igényeinek leginkább megfelel.
Válasz
Felületek használatával megoldhatja a körfüggőséget.
Aktuális kialakítás:
Javasolt kialakítás:
A javasolt terv betonban osztályok nem függenek más konkrét osztályoktól, hanem csak az absztrakcióktól (interfészektől).
Fontos:
A kiválasztott kreatív mintát kell használnia (esetleg gyári), hogy elkerülje a megjelenést new
bármely konkrét osztály bármely más betonosztályon belül, vagy hívja az getInstance()
-t. Csak a gyár függ a konkrét osztályoktól. Main
osztálya gyárként szolgálhat, ha úgy gondolja, hogy egy dedikált gyár túlteljes lenne. Például beadhat egy ReportGenerator
fájlt a TestExecuter
fájlba ahelyett, hogy hívja az getInstance()
vagy new
.
Válasz
Mivel TestExecutor
csak belsőleg használja a ReportGenerator
-et, akkor képesnek kell lennie arra, hogy meghatározzon egy interfészt hozzá, és utaljon a TestScenario
-re. Ekkor TestExecutor
a ReportGenerator
, a ReportGenerator
TestScenario
és TestScenario
a ITestExecutor
függvénye, amely nem függ semmitől.
Ideális esetben Ön “határozzon meg interfészeket az összes osztály számára, és fejezze ki azokon keresztül a függőségeket, de ez a legkisebb változás, amely megoldja a problémát.
File(filename).write(Report); Report = XMLResult(ResultData).toString(); ResultData = TestSuite(SingleTestLogic).execute(TestDataIterator(TestDetailsList))