순환 의존성을 해결하는 방법?


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

편집 : 답변에 대한 응답으로 내 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))
전율

답변:


35

기술적으로는 다른 답변에 표시된 것처럼 인터페이스를 사용하여 순환 종속성을 해결할 수 있습니다. 그러나 디자인을 다시 생각하는 것이 좋습니다. 나는 당신이 할 수 가능성이 아니라고 생각 하지 않도록 설계는 더 간단하게하면서, 완전히 추가 인터페이스가 필요합니다.

나는 직접 ReportGenerator의존 할 필요가 없다고 생각합니다 TestScenario. TestScenario테스트 실행에 사용되며 결과에 대한 컨테이너로도 작동합니다. 이것은 SRP 위반입니다. 흥미롭게도, 위반을 해결함으로써 주기적 의존성을 제거 할 수 있습니다.

따라서 보고서 생성기가 테스트 시나리오에서 데이터를 가져 오는 대신 값 개체를 사용하여 명시 적으로 데이터를 전달합니다. 즉, 교체

   reportGenerator.setTestScenario(ts); 

같은 코드로

reportGenerator.insertDataToDisplay(ts.getReportData()); 

이 메서드 에는 보고서에 데이터를 표시하기위한 컨테이너 역할을하는 value 개체 getReportData와 같은 반환 형식이 있어야합니다 ReportData. insertDataToDisplay정확히 해당 유형의 객체를 예상하는 방법입니다.

이 방법은, ReportGenerator그리고 TestScenario모두에 따라 달라집니다 ReportData, 아무것도에 의존하고, 처음 두 클래스는 더 이상 서로에 의존하지 않습니다.

두 번째 접근법 : SRP 위반을 해결하기 위해 TestScenario테스트 실행 결과를 보유해야하지만 테스트 실행자를 호출하지는 마십시오. 테스트 시나리오가 테스트 실행기에 액세스하지 않고 테스트 실행기가 외부에서 시작되어 결과를 다시 TestScenario오브젝트에 기록하도록 코드를 재구성하십시오 . 당신이 우리에게 보여준 예에서, 그것은 대중의 LinkedList<Test>내부에 접근 TestScenario하고 execute메소드 TestScenario를 다른 곳으로, 아마도 직접 TestExecuter, 새로운 클래스로 이동시킴으로써 가능할 것 TestScenarioExecuter입니다.

그렇게하면 ~에 TestExecuter의존하고 TestScenario~ ReportGeneratorReportGenerator의존 TestScenario하지만 TestScenario다른 것에 의존 하지는 않습니다.

마지막으로, 세 번째 접근 방식 TestExecuter은 너무 많은 책임이 있습니다. 테스트를 수행하고에를 제공 TestScenario해야합니다 ReportGenerator. 이 두 가지 책임을 두 개의 개별 클래스에두면 순환 종속성이 다시 사라집니다.

문제에 접근 할 수있는 더 많은 변형이있을 수 있지만 일반적인 문제는 다음과 같습니다. 핵심 문제는 너무 많은 책임 이있는 클래스입니다 . 이 문제를 해결하면 순환 종속성을 자동으로 제거합니다.


덕분에 당신의 대답을 실제로 나는 :( 끝에 내 보고서를 생성 할 수 TestScenario의 모든 정보가 필요
sabrina2020

@ sabrina2020 : 그리고 그 정보를 모두 넣는 데 방해가되는 것은 무엇 ReportData입니까? 질문을 수정하고 내부에서 발생하는 일에 대해 좀 더 자세히 설명해보십시오 saveReport.
Doc Brown

실제로 내 TestScenario에는 Test 목록이 포함되어 있으며 보고서 XML 파일의 모든 정보를 원하므로 ReportData 에이 정보가 모두 있어야합니다. 자세한 내용은 답변을 편집하여 감사합니다!
sabrina2020

1
+1 : 당신은 저를 가졌습니다 interfaces.
Joel Etherton

@ sabrina2020 : 내 대답에 두 가지 다른 접근법을 추가했습니다. 필요에 가장 적합한 것을 선택하십시오.
Doc Brown

8

인터페이스를 사용하면 순환 종속성을 해결할 수 있습니다.

현재 디자인 :

여기에 이미지 설명을 입력하십시오

제안 된 디자인 :

여기에 이미지 설명을 입력하십시오

제안 된 설계에서 구체적인 클래스는 다른 구체적인 클래스에 의존하지 않고 추상화 (인터페이스)에만 의존합니다.

중대한:

다른 콘크리트 클래스 내부의 콘크리트 클래스의 퍼포밍 또는 호출 을 피하려면 선택한 생성 패턴 (아마도 공장) 을 사용해야합니다 . 팩토리 만이 콘크리트 클래스에 의존합니다. 귀하 는 전용 공장은 과도하다고 생각하는 경우 클래스는 공장의 역할을 할 수있다. 예를 들어, 당신은을 주입 할 수 있습니다 에 호출하는 대신 나 .newgetInstance()MainReportGeneratorTestExecutergetInstance()new


3

내부적으로 TestExecutor만 사용 되므로 ReportGenerator인터페이스를 정의하고의 인터페이스를 참조 할 수 있어야합니다 TestScenario. 그런 다음 TestExecutor에 따라 ReportGenerator, ReportGenerator의존 TestScenario, 그리고 TestScenario에 따라 ITestExecutor아무것도에 의존하지 않는다.

이상적으로 모든 클래스에 대한 인터페이스를 정의하고 클래스를 통해 종속성을 표현하는 것이 가장 좋지만 문제를 해결하는 가장 작은 변경입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.