0

JavaFX 응용 프로그램을 만들고 4 개의 루트 컨트롤러가 있습니다. 이들 각각은 탭에서보기를 제어합니다. 표시 할 네 개의보기 중 하나를 선택하는 것 외에 다른 기능이 없으므로 탭 선택기의 컨트롤러가 없습니다. 이 컨트롤러는 동일한 데이터에 액세스해야하며이 데이터를 모두 수정할 수 있습니다.의존성 삽입 또는 관찰자 이외의 Java에서의 싱글 톤 패턴 대체

읽을 수있는 방식으로이 작업을 수행하는 유일한 방법은 네 개의 모든 컨트롤러에서 액세스하고 수정할 수있는 상태를 저장하는 정적 싱글 톤을 사용하는 것입니다. 명백한 이유 때문에 이것은 이상적이지 않습니다.

앱이 시작될 때 모든 컨트롤러가 초기화되므로 종속성 삽입을 사용할 수 없습니다. 서로에 의해 만들어지지 않습니다. 같은 이유로 나는 관찰자를 사용할 수 없다. 그들은 서로에 대한 참조를 얻을 수있는 방법이 없으므로 서로를 관찰 할 수 없습니다. 지금까지 내가 아는 한 Java의 브로드 캐스트 알림 시스템은 해결책이 될 수 있으므로 귀찮습니다. 제가 사용할 수있는 또 다른 패턴이 있습니까? 아니면 이러한 패턴 작업 중 하나를 만들 수있는 방법이 있습니까?

탭의 fxml 파일은 탭 창에 내용으로로드됩니다. 이렇게하면 각 탭마다 다른 컨트롤러를 가질 수 있습니다. 그런 다음 start 메소드는 탭 창 fxml을로드합니다.

<TabPane prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER"> 
     <tabs> 
      <Tab text="Data &amp; Statistics"> 
      <content> 
       <fx:include fx:id="dataViewTabControl" source="DataViewTabControl.fxml" /> 
      </content> 
      </Tab> 
      . . . 
+1

[전달 매개 변수 JavaFX FXML] (http://stackoverflow.com/questions/14187963/passing-parameters-javafx-fxml)의 가능한 복제본 – fabian

+0

이들은 FXML 방식의 컨트롤러입니까? 네 개의 탭에 대한 네 개의 FXML 파일은 어디에로드됩니까? –

+0

이들은 다음과 같이 탭의 내용으로 탭 창에로드됩니다. – Matt

답변

2

당신은 효과적으로 FXMLLoader에 컨트롤러 공장을 설정하여 의존성 주입을 사용할 수 있습니다. 이를 통해 제어기 클래스 fx:controller 속성을 지정하는 FXML 파일에 대해 컨트롤러 인스턴스가 작성되는 방법을 제어 할 수 있습니다. 컨트롤러 팩토리는 기본 FXML 파일뿐만 아니라 포함 된 FXML 파일에도 사용됩니다.

따라서 응용 프로그램 상태로 모델 클래스를 만들고 컨트롤러에서 해당 상태를 관찰 및 수정하고 모든 컨트롤러간에 공유되는 단일 인스턴스를 만들 수 있습니다. 이 같은 컨트롤러와 DataViewTabControl.fxml 파일을 정의한다면

public class Model { /* ... */ } 

:

모델 정의

<?xml version="1.0" encoding="UTF-8"?> 

<!-- imports etc --> 

<SomeRootPane fx:controller="com.example.DataViewTabController"> 

    <!-- ... --> 

</SomeRootPane> 

그리고 정의를 당신의 DataViewTabController 생성자에 Model 매개 변수를 사용하는 :

public class DataViewTabController { 

    private final Model model ; 

    public DataViewTabController(Model model) { 
     this.model = model ; 
    } 

} 

이제

Model model = new Model(); 

FXMLLoader loader = new FXMLLoader(getClass().getResource("/path/to/fxml/file")); 

loader.setControllerFactory((Class<?> controllerType) -> { 
    try { 
     for (Constructor<?> con : controllerType.getConstructors()) { 
      if (con.getParameterCount() == 1 && con.getParameterTypes()[0]==Model.class) { 
       return con.newInstance(model); 
      } 
     } 
     // no suitable constructor found: just return default instance 
     return controllerType.newInstance(); 
    } catch (Exception e) { 
     System.err.println("Warning: could not load controller"); 
     e.printStackTrace(System.err); 
     return null ; 
    } 
}); 
이제

모든 컨트롤러 : 동일한 작업을 수행하거나 생성자 매개 변수로 모델을 컨트롤러 나 <fx:include>들 수있다 주요 FXML 파일 및 다른 파일이 올바른 생성자를 호출하는 컨트롤러 공장을 사용 같은 Model 인스턴스에 액세스 할 수 있으므로 일반적인 MVC/관찰자 패턴을 사용하여 데이터를 변경하고 데이터의 변경 내용에 응답 할 수 있습니다. 모델 클래스가 JavaFX property API을 사용하는 경우 특히 쉽습니다.

+0

이것은 완벽합니다. 나는 컨트롤러 공장에 대해 들어 보지 못했다. – Matt

+0

@Matt이 기술을 사용하여 JavaFX와 종속성 주입 프레임 워크를 결합 할 수도 있습니다. 예 : Spring을 사용한다면, 모든 컨트롤러를 스프링 관리 빈으로 만드십시오 (그래서 모델 인스턴스를 직접 삽입 할 수 있습니다). 그런 다음'ApplicationContext context;를 주면'fxmlLoader.setControllerFactory (context :: getBean);'를 할 수 있습니다. 그런 다음 FXMLLoader는 스프링 응용 프로그램 컨텍스트에서 모든 컨트롤러 인스턴스를 요청합니다. –

+0

한번 시도해 보겠습니다. 도와 주셔서 감사합니다. – Matt