Kuinka ratkaista pyöreä riippuvuus?
On tammikuu 1, 2021 by adminMinulla on kolme luokkaa, jotka ovat riippuvaisia toisistaan:
TestExecuter suorittaa TestScenario-pyynnöt ja tallentaa raporttitiedoston ReportGenerator-luokan avulla . Joten:
- TestExecuter riippuu ReportGeneratorista raportin luomisessa
- ReportGenerator riippuu TestScenario-ohjelmasta ja TestExecuter-ohjelmasta asetetuista parametreista.
- TestScenario riippuu TestExecuter-ohjelmasta.
Ei voida selvittää, miten näiden riippuvuudet poistetaan.
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() } }
MUOKKAA: vastauksena vastaus, lisätietoja TestScenario-luokastani:
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 */ }
Esimerkki xml-tiedosto, joka luodaan skenaariossa, joka sisältää kaksi testiä:
<testScenario name="scenario1"> <test name="test1"> <result>false</result> </test> <test name="test1"> <result>true</result> </test> </testScenario >
Kommentit
Vastaa
Teknisesti voit ratkaista kaikki sykliset riippuvuudet käyttöliittymien avulla, kuten muissa vastauksissa on esitetty. Suosittelen kuitenkin miettimään muotoilusi uudelleen. Mielestäni ei ole epätodennäköistä, että voit välttää lisärajapintojen tarpeen kokonaan, kun taas suunnittelustasi tulee vielä yksinkertaisempi.
Luulen, että ReportGenerator
ei tarvitse olla riippuvainen suoraan TestScenario
. TestScenario
näyttää olevan kaksi vastuuta: sitä käytetään testin suorittamiseen ja se toimii myös tulosten säilönä. Tämä on SRP: n vastaista. Mielenkiintoista on, että ratkaisemalla kyseisen rikkomuksen pääset eroon myös syklisestä riippuvuudesta.
Joten sen sijaan, että annat raporttigeneraattorin napata tietoja testiskenaariosta, välitä tiedot nimenomaisesti käyttämällä jotakin arvoobjektia. Tämä tarkoittaa, korvaa
reportGenerator.setTestScenario(ts);
jollakin koodilla, kuten
reportGenerator.insertDataToDisplay(ts.getReportData());
Metodi getReportData
on oltava palautustyyppi, kuten ReportData
, arvo-objekti, joka toimii säilössä raportissa näytettäville tiedoille. insertDataToDisplay
on menetelmä, joka odottaa juuri tämän tyyppistä objektia.
Tällä tavalla ReportGenerator
ja TestScenario
riippuu molemmista ReportData
, joka ei riipu mistään muusta, ja kaksi ensimmäistä luokkaa eivät ole enää riippuvaisia toisistaan.
Toisena lähestymistapana: ratkaise SRP-rikkomus, anna TestScenario
olla vastuussa testin suorituksen tulosten pitämisestä, mutta ei kutsun suorittamisesta. Harkitse koodin uudelleenjärjestämistä, jotta testiskenaario ei pääse testin suorittajalle, mutta testin suoritin käynnistetään ulkopuolelta ja kirjoittaa tulokset takaisin objektiin TestScenario
. Näytimme meille esimerkissä, että se on mahdollista tekemällä pääsy LinkedList<Test>
-palveluun TestScenario
-palvelun sisällä ja siirtämällä execute
menetelmä TestScenario
jonnekin muualle, ehkä suoraan TestExecuter
, ehkä uudelle luokalle TestScenarioExecuter
.
Tällä tavoin TestExecuter
riippuu TestScenario
ja ReportGenerator
, ReportGenerator
riippuu myös TestScenario
, mutta TestScenario
ei riipu mistään muusta.
Ja lopuksi kolmannella lähestymistavalla: TestExecuter
on myös liian monta vastuuta. Se on vastuussa testien suorittamisesta sekä TestScenario
-palvelun toimittamisesta ReportGenerator
-palveluun. Laita nämä kaksi vastuuta kahteen erilliseen luokkaan, ja syklinen riippuvuutesi katoaa jälleen.
Ongelmaasi voi olla enemmän, mutta toivon, että saat yleisen ajatuksen: ydinongelmasi on luokkia div id = ”758f50fbd4”>
liian monta vastuuta . Ratkaise ongelma ja pääset eroon syklisestä riippuvuudesta automaattisesti.
Kommentit
- Kiitos vastauksestasi, itse asiassa tarvitsen kaikki tiedot TestScenaariossa voin luoda raporttini lopussa 🙁
- @ sabrina2020: ja mikä estää sinua sijoittamasta kaikkia näitä tietoja osioon
ReportData
?Voit harkita kysymyksesi muokkaamista ja selittää hieman yksityiskohtaisemmin, mitä tapahtuusaveReport
-tilassa. - Itse asiassa TestScenaario sisältää luettelon testistä ja haluan kaikki tiedot raportin xml-tiedostossa, joten ReportDatalla on kaikki tässä tapauksessa, muokkaan vastaustani saadaksesi lisätietoja, kiitos!
- +1: Sinulla oli minut osoitteessa
interfaces
. - @ sabrina2020: Lisäsin vastaukseeni kaksi erilaista lähestymistapaa, valitse se, joka sopii parhaiten tarpeisiisi.
Vastaa
Liitäntöjen avulla voit ratkaista pyöreän riippuvuuden.
Nykyinen suunnittelu:
Ehdotettu malli:
Ehdotetussa suunnittelukokonaisuudessa luokat eivät riipu muista konkreettisista luokista, mutta vain abstraktioista (rajapinnoista).
Tärkeää:
Sinun on käytettävä valitsemasi luontikuviota (ehkä tehdas) välttääksesi tuloa new
mistä tahansa betoniluokasta minkä tahansa muun betoniluokan sisällä tai soittamalla getInstance()
. Vain tehtaalla on riippuvuus betoniluokista. Main
-luokkasi voisi toimia tehtaana, jos uskot, että oma tehdas olisi ylivoimainen. Voit esimerkiksi pistää ReportGenerator
kohtaan TestExecuter
sen sijaan, että soittaisit getInstance()
tai new
.
Vastaa
Koska TestExecutor
käyttää vain ReportGenerator
sisäisesti, sinun pitäisi pystyä määrittelemään sille käyttöliittymä ja viittaamaan käyttöliittymään kohdassa TestScenario
. Sitten TestExecutor
riippuu ReportGenerator
, ReportGenerator
riippuu TestScenario
ja TestScenario
riippuu ITestExecutor
, joka ei ole riippuvainen mistään.
Ihannetapauksessa sinä ”Määritä kaikkien luokkien rajapinnat ja ilmaise riippuvuuksia niiden kautta, mutta tämä on pienin muutos, joka ratkaisee ongelmasi.
File(filename).write(Report); Report = XMLResult(ResultData).toString(); ResultData = TestSuite(SingleTestLogic).execute(TestDataIterator(TestDetailsList))