swing
MVP 패턴
수색…
간단한 MVP 예제
MVP 패턴의 간단한 사용법을 설명하기 위해 버튼과 레이블 만있는 간단한 UI를 만드는 다음 코드를 살펴보십시오. 버튼을 클릭하면 버튼이 클릭 된 횟수와 함께 라벨이 업데이트됩니다.
우리에게는 5 가지 수업이 있습니다 :
- 모델 - 상태를 유지할 POJO (MVP에서 M)
- 보기 - UI 코드가있는 클래스 (MVP의 V)
- ViewListener - 뷰 내의 액션에 응답하는 메소드를 제공하는 인터페이스
- 발표자 - 입력에 응답하고보기를 업데이트합니다 (MVP의 P).
- 응용 프로그램 - 모든 것을 하나로 모아 응용 프로그램을 시작하는 "기본"클래스
단일 count
변수 만 유지하는 최소한의 "모델"클래스입니다.
/**
* A minimal class to maintain some state
*/
public class Model {
private int count = 0;
public void addOneToCount() {
count++;
}
public int getCount() {
return count;
}
}
청취자에게 알리기위한 최소한의 인터페이스 :
/**
* Provides methods to notify on user interaction
*/
public interface ViewListener {
public void onButtonClicked();
}
뷰 클래스는 모든 UI 요소를 생성합니다. 보기 및보기 만 UI 요소 (예 : 발표자 또는 다른 클래스의 단추, 텍스트 필드 없음)에 대한 참조를 가져야합니다.
/**
* Provides the UI elements
*/
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;
public class View {
// A list of listeners subscribed to this view
private final ArrayList<ViewListener> listeners;
private final JLabel label;
public View() {
final JFrame frame = new JFrame();
frame.setSize(200, 100);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout());
final JButton button = new JButton("Hello, world!");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
notifyListenersOnButtonClicked();
}
});
frame.add(button);
label = new JLabel();
frame.add(label);
this.listeners = new ArrayList<ViewListener>();
frame.setVisible(true);
}
// Iterate through the list, notifying each listner individualy
private void notifyListenersOnButtonClicked() {
for (final ViewListener listener : listeners) {
listener.onButtonClicked();
}
}
// Subscribe a listener
public void addListener(final ViewListener listener) {
listeners.add(listener);
}
public void setLabelText(final String text) {
label.setText(text);
}
}
통지 논리는 Java8에서 다음과 같이 코딩 될 수도 있습니다.
...
final Button button = new Button("Hello, world!");
// In order to do so, our interface must be changed to accept the event parametre
button.addActionListener((event) -> {
notifyListeners(ViewListener::onButtonClicked, event);
// Example of calling methodThatTakesALong, would be the same as callying:
// notifyListeners((listener, long)->listener.methodThatTakesALong(long), 10L)
notifyListeners(ViewListener::methodThatTakesALong, 10L);
});
frame.add(button);
...
/**
* Iterates through the subscribed listeneres notifying each listener individually.
* Note: the {@literal '<T>' in private <T> void} is a Bounded Type Parametre.
*
* @param <T> Any Reference Type (basically a class).
*
* @param consumer A method with two parameters and no return,
* the 1st parametre is a ViewListner,
* the 2nd parametre is value of type T.
*
* @param data The value used as parametre for the second argument of the
* method described by the parametre consumer.
*/
private <T> void notifyListeners(final BiConsumer<ViewListener, T> consumer, final T data) {
// Iterate through the list, notifying each listener, java8 style
listeners.forEach((listener) -> {
// Calls the funcion described by the object consumer.
consumer.accept(listener, data);
// When this method is called using ViewListener::onButtonClicked
// the line: consumer.accept(listener,data); can be read as:
// void accept(ViewListener listener, ActionEvent data) {
// listener.onButtonClicked(data);
// }
});
}
ActionEvent를 매개 변수로 사용하려면 인터페이스를 리팩토링해야합니다.
public interface ViewListener {
public void onButtonClicked(ActionEvent evt);
// Example of methodThatTakesALong signature
public void methodThatTakesALong(long );
}
여기에서는 하나의 notify-method 만 필요하다. 실제 리스너 메소드와 매개 변수는 매개 변수로 전달된다. 필요한 경우 실제 이벤트 처리보다 조금 덜 능숙하게 사용할 수도 있지만 인터페이스에 메서드가있는 한 모두 작동합니다 (예 :
notifyListeners(ViewListener::methodThatTakesALong, -1L);
발표자는보기를 받아서 청취자로 추가 할 수 있습니다. 보기에서 단추를 클릭하면보기가 모든 수신기 (발표자 포함)에 알립니다. 발표자에게 알리면 모델 (즉, 응용 프로그램의 상태)을 업데이트하고 그에 따라 뷰를 업데이트하는 적절한 조치가 취해질 수 있습니다.
/**
* Responsible to responding to user interaction and updating the view
*/
public class Presenter implements ViewListener {
private final View view;
private final Model model;
public Presenter(final View view, final Model model) {
this.view = view;
view.addListener(this);
this.model = model;
}
@Override
public void onButtonClicked() {
// Update the model (ie. the state of the application)
model.addOneToCount();
// Update the view
view.setLabelText(String.valueOf(model.getCount()));
}
}
모든 것을 하나로 모으기 위해 뷰를 생성하여 발표자에게 주입 할 수 있습니다. 마찬가지로, 초기 모델을 생성하고 주입 할 수 있습니다. 두 가지 모두 발표자에서 만들 수 있지만 생성자에 삽입하면 훨씬 간단하게 테스트 할 수 있습니다.
public class Application {
public Application() {
final View view = new View();
final Model model = new Model();
new Presenter(view, model);
}
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Application();
}
});
}
}