परिपत्र निर्भरता कैसे हल करें?


33

मेरे पास तीन वर्ग हैं जो एक दूसरे के लिए परिपत्र हैं:

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()
    }
}

EDIT: एक जवाब के जवाब में, मेरे टेस्टसेनारियो वर्ग के बारे में अधिक जानकारी:

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))
shudder

जवाबों:


35

तकनीकी रूप से, आप इंटरफेस का उपयोग करके किसी भी चक्रीय निर्भरता को हल कर सकते हैं, जैसा कि अन्य उत्तरों में दिखाया गया है। हालांकि, मैं आपके डिज़ाइन पर पुनर्विचार करने की सलाह देता हूं। मुझे लगता है कि यह संभावना नहीं है कि आप अतिरिक्त इंटरफेस की आवश्यकता से पूरी तरह से बच सकते हैं , जबकि आपका डिज़ाइन और भी सरल हो जाता है।

मुझे लगता है कि यह आवश्यक नहीं है कि वह सीधे ReportGeneratorनिर्भर हो TestScenarioTestScenarioलगता है कि दो ज़िम्मेदारियाँ हैं: इसका उपयोग परीक्षण निष्पादन के लिए किया जाता है, और यह परिणामों के लिए एक कंटेनर के रूप में भी काम करता है। यह एसआरपी का उल्लंघन है। दिलचस्प है, उस उल्लंघन को हल करने से, आपको चक्रीय निर्भरता से भी छुटकारा मिलेगा।

इसलिए रिपोर्ट जनरेटर को परीक्षण परिदृश्य से डेटा हड़पने के बजाय, कुछ मूल्य वस्तु का उपयोग करके स्पष्ट रूप से डेटा पास करें। इसका मतलब है, प्रतिस्थापित करें

   reportGenerator.setTestScenario(ts); 

कुछ कोड की तरह

reportGenerator.insertDataToDisplay(ts.getReportData()); 

विधि getReportDataको रिटर्न प्रकार की आवश्यकता होती है जैसे ReportData, एक मान ऑब्जेक्ट जो रिपोर्ट में प्रदर्शित किए जाने वाले डेटा के लिए एक कंटेनर के रूप में काम करता है। insertDataToDisplayएक ऐसी विधि है जो उस प्रकार की वस्तु की अपेक्षा रखती है।

इस तरह, ReportGeneratorऔर TestScenarioदोनों पर निर्भर करेगा ReportData, जो कुछ और नहीं पर निर्भर करता है, और पहले दो वर्ग एक दूसरे पर निर्भर नहीं करते हैं।

दूसरे दृष्टिकोण के रूप में: एसआरपी उल्लंघन को हल करने के TestScenarioलिए एक परीक्षण निष्पादन के परिणामों को रखने के लिए जिम्मेदार होना चाहिए, लेकिन परीक्षण निष्पादन को कॉल करने के लिए नहीं। कोड को पुनर्गठित करने पर विचार करें ताकि परीक्षण परिदृश्य परीक्षण के निष्पादन तक न पहुंच पाए, लेकिन परीक्षण निष्पादित कंप्यूटर को बाहर से शुरू किया जाता है और परिणामों को वापस TestScenarioवस्तु में लिखता है । उदाहरण में आपने हमें दिखाया, जो कि सार्वजनिक रूप से LinkedList<Test>अंदर तक पहुंच बनाकर और संभवत: विधि को कहीं और TestScenarioले जाकर , शायद सीधे एक नए वर्ग में ले जाने से संभव होगा ।executeTestScenarioTestExecuterTestScenarioExecuter

इस तरह, TestExecuterइस पर निर्भर करेगा TestScenarioऔर ReportGenerator, ReportGeneratorइस पर निर्भर करेगा TestScenario, भी, लेकिन TestScenarioकुछ नहीं पर निर्भर करेगा।

और अंत में, एक तीसरे दृष्टिकोण: के TestExecuterपास बहुत अधिक जिम्मेदारियां हैं, भी। यह परीक्षणों को निष्पादित करने के साथ-साथ ए प्रदान करने के लिए भी जिम्मेदार TestScenarioहै ReportGenerator। इन दो जिम्मेदारियों को दो अलग-अलग वर्गों में रखें, और आपकी चक्रीय निर्भरता फिर से गायब हो जाएगी।

आपकी समस्या से संपर्क करने के लिए और अधिक संस्करण हो सकते हैं, लेकिन मुझे आशा है कि आपको सामान्य विचार मिलेगा: आपकी मुख्य समस्या बहुत अधिक जिम्मेदारियों के साथ कक्षाएं हैं । उस समस्या को हल करें, और आप चक्रीय निर्भरता से स्वचालित रूप से छुटकारा पा लेंगे।


आपके उत्तर के लिए धन्यवाद, वास्तव में मुझे TestScenario में सभी जानकारी की आवश्यकता है ताकि मैं अंत में अपनी रिपोर्ट तैयार कर
सकूं

@ sabrina2020: और आपको वह सारी जानकारी डालने में क्या बाधा है ReportData? आप अपने प्रश्न को संपादित करने पर विचार कर सकते हैं और थोड़ा और विस्तृत बता सकते हैं कि अंदर क्या होता है saveReport
डॉक्टर ब्राउन

वास्तव में मेरे TestScenario में टेस्ट की एक सूची है और मुझे एक रिपोर्ट xml फ़ाइल में सभी जानकारी चाहिए, इसलिए ReportData में यह सब होगा, मैं अधिक विवरण के लिए अपना उत्तर संपादित करूंगा, धन्यवाद!
सबरीना 2020 14

1
+1: आपने मुझे देखा था interfaces
जोएल एथरटन

@ sabrina2020: मैंने अपने उत्तर में दो अलग-अलग दृष्टिकोण जोड़े, जो आपकी आवश्यकताओं के अनुरूप हो, उसे चुनें।
डॉक्टर ब्राउन

8

इंटरफेस का उपयोग करके आप परिपत्र निर्भरता को हल कर सकते हैं।

मौजूदा डिज़ाइन:

यहाँ छवि विवरण दर्ज करें

प्रस्तावित डिजाइन:

यहाँ छवि विवरण दर्ज करें

प्रस्तावित डिजाइन में ठोस वर्ग अन्य कंक्रीट कक्षाओं पर निर्भर नहीं करते हैं, केवल सार (इंटरफेस) पर होते हैं।

जरूरी:

आपको किसी भी अन्य ठोस वर्ग या कॉलिंग के अंदर किसी भी ठोस कक्षाओं को पूरा करने से बचने के लिए अपनी पसंद (शायद एक कारखाना) के रचनात्मक पैटर्न का उपयोग करना होगा । केवल कारखाने में ठोस वर्गों पर निर्भरता होगी। यदि आपको लगता है कि एक समर्पित कारखाना ओवरकिल होगा, तो आपकी कक्षा कारखाने के रूप में काम कर सकती है। उदाहरण के लिए आप कॉल या के बजाय एक में इंजेक्ट कर सकते हैं ।newgetInstance()MainReportGeneratorTestExecutergetInstance()new


3

चूंकि TestExecutorकेवल ReportGeneratorआंतरिक रूप से उपयोग करता है , इसलिए आपको इसके लिए एक इंटरफ़ेस को परिभाषित करने में सक्षम होना चाहिए, और इंटरफ़ेस को संदर्भित करना चाहिए TestScenario। फिर TestExecutorनिर्भर करता है ReportGenerator, ReportGeneratorनिर्भर करता है TestScenario, और TestScenarioनिर्भर करता है ITestExecutor, जो किसी भी चीज पर निर्भर नहीं करता है।

आदर्श रूप से आप अपने सभी वर्गों के लिए इंटरफेस को परिभाषित करेंगे और उनके माध्यम से निर्भरता व्यक्त करेंगे, लेकिन यह सबसे छोटा बदलाव है जो आपकी समस्या को हल करेगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.