Ehh, mam wrażenie, że próbujesz to zrobić jakoś tak na siłę. Po co Ci ten abstakcyjny model? Przygotowałem Ci gotowy przykład z opisem. Jest to okienkowa aplikacja ze stoperem :P. W załączniku projekt IntelliJ.
Klasa Main - nic szczególnego, ale żeby było kompletnie:
public class Main {
public static void main(String[] args) {
MainFrame mainFrame = new MainFrame();
mainFrame.setVisible(true);
}
}
Interfejsy - ICounterChangeListener oraz ICounterView.
public interface ICounterChangeListener {
void onCounterChanged();
}
public interface ICounterView {
void displayCounterValue(int counterValue);
}
Zaczyna się robić ciekawie - klasa modelu - Counter
. Daje możliwosć zwiększania wartości co 1 sekundę. O zmianie wartości informuje swoich słuchaczy.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class Counter {
private int value;
private List<ICounterChangeListener> changeListeners = new ArrayList<>();
private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
private ScheduledFuture currentTimer;
public Counter() {
}
private void notifyChangeListeners() {
for (ICounterChangeListener listener : changeListeners) {
listener.onCounterChanged();
}
}
private void increaseValue() {
value++;
notifyChangeListeners();
}
public int getValue() {
return value;
}
public void start() {
value = 0;
if (currentTimer == null) {
currentTimer = executor.scheduleAtFixedRate(() -> increaseValue(), 0, 1, TimeUnit.SECONDS);
}
}
public void addChangeListener(ICounterChangeListener listener) {
changeListeners.add(listener);
}
public void removeChangeListener(ICounterChangeListener listener) {
changeListeners.remove(listener);
}
public void stop() {
if (currentTimer != null) {
currentTimer.cancel(true);
currentTimer = null;
value = 0;
notifyChangeListeners();
}
}
}
Klasa Prezentera, reaguje na zdarzenia GUI oraz na zmiany Modelu. Komunikuje zmiany Modelu Widokowi (poprzez ICounterView). Prezenter (podobnie jak Kontroler) powinien być możliwie chudziutki i delegować zadania.
public class MainFramePresenter implements ICounterChangeListener {
private final ICounterView counterView;
private Counter counter = new Counter();
public MainFramePresenter(ICounterView counterView) {
this.counterView = counterView;
this.counter.addChangeListener(this);
}
@Override
public void onCounterChanged() {
this.counterView.displayCounterValue(counter.getValue());
}
public void startCounter() {
this.counter.start();
}
public void stopCounter() {
this.counter.stop();
}
}
Na koniec implementacja widoku (zrobiona raczej od niechcenia, byle było :P)
import javax.swing.*;
public class MainFrame extends JFrame implements ICounterView {
private JLabel lCounterValue;
private MainFramePresenter presenter;
public MainFrame() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
initializeGUI();
presenter = new MainFramePresenter(this);
}
private void initializeGUI() {
setTitle("Counter");
setResizable(false);
setSize(250, 100);
lCounterValue = new JLabel();
JPanel labelPanel = new JPanel();
labelPanel.setSize(100, 15);
labelPanel.setLocation(10, 10);
labelPanel.add(lCounterValue);
JButton btnStartCounter = new JButton("Start");
btnStartCounter.setSize(100, 15);
btnStartCounter.setLocation(10, 40);
btnStartCounter.addActionListener((evt) -> presenter.startCounter());
JButton btnStopCounter = new JButton("Stop");
btnStopCounter.setSize(100, 15);
btnStopCounter.setLocation(120, 40);
btnStopCounter.addActionListener((evt) -> presenter.stopCounter());
getContentPane().add(btnStopCounter);
getContentPane().add(btnStartCounter);
getContentPane().add(labelPanel);
}
@Override
public void displayCounterValue(final int counterValue) {
SwingUtilities.invokeLater(() -> lCounterValue.setText(String.valueOf(counterValue)));
}
}