MVC con diversi pattern MVC e gameloop

-1

Ho creato un piccolo programma usando diversi pattern MVC. Finora non ho avuto molto materiale da inserire nel modello, quindi non ho ancora ottenuto alcun modello.

La mia idea è di creare un pattern MVC per ciascun pannello. E facendolo scorrere nel mainloop in MainController . Quindi comunico (avvio e arresto) con MainLoop nel MainController passando il MainController come parametro per i "subcontroller" PanOneController e PanTwoController .

In questo modo:

Main | MainView | MainController (mainloop)

PanelOne Model | PanelOne View | PanelOne Controller

PanelTwo Model | PanelTwo View | PanelTwo Controller

Questa sarebbe considerata una buona struttura? O qualche altro suggerimento della struttura?

Questo è solo un esempio. Sto andando ad aggiungere più pannelli e funzioni, ma voglio solo ottenere la struttura giusta.

Grazie per il feedback!

Principale

import javax.swing.SwingUtilities;

public class Main {

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                MainView theView = new MainView();
                MainModel theModel = new MainModel();
                MainController theController = new MainController(theView, theModel);
                theView.setVisible(true);
            }
        });
    }
}

Visualizza

import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import panelTwo.PanTwoView;
import panelOne.PanOneView;

public class MainView extends JFrame {

    PanOneView oneV = new PanOneView();
    PanTwoView twoV = new PanTwoView();

    JPanel panelOne = oneV;
    JPanel panelTwo = twoV;

    public MainView() {
        setLayout(new FlowLayout(FlowLayout.LEFT, 100, 10));
        setSize(new Dimension(300, 200));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.add(panelOne);
        this.add(panelTwo);
    }

    public PanOneView getPanelOne() {
        return oneV;
    }

    public PanTwoView getPanelTwo() {
        return twoV;
    }
}

CONTROLLER

import panelOne.*;
import panelTwo.*;

public class MainController implements Runnable {

    private Thread thread;
    private boolean running = false;

    MainView theView;
    MainModel theModel;

    PanOneModel oneM = new PanOneModel();
    PanTwoModel twoM = new PanTwoModel();

    PanOneController oneC;
    PanTwoController twoC;

    private int inc = 0;

    public MainController(MainView x, MainModel y) {
        this.theView = x;
        this.theModel = y;
        thread = new Thread(this);
        oneC = new PanOneController(oneM, x.getPanelOne(), this);
        twoC = new PanTwoController(twoM, x.getPanelTwo(), this);
    }

    public synchronized void start() {
        if (!running) {
            thread = new Thread(this);
            thread.start();
        }
        running = true;
    }

    public synchronized void stop() {
        thread.interrupt();
        running = false;
    }

    // mainloop
    public void run() {
        boolean shifter = false;
        long timer = 0;
        while (running) {
            if (System.nanoTime() - timer >= 1000000) {
                timer = System.nanoTime();
                inc++;
                if (inc % 1000 == 0) {
                    shifter = !shifter;
                }
                oneC.run(shifter);
                twoC.run(shifter);
            }
        }
    }
}

PANELONE VIEW

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class PanOneView extends JPanel {

    private JLabel jl = new JLabel("PANEL 1");
    private JButton start = new JButton("Start");

    public PanOneView() {
        this.setPreferredSize(new Dimension(100, 50));
        this.setBackground(Color.red);
        jl.setForeground(new java.awt.Color(255, 255, 255));
        add(jl);
        add(start);
    }

    public void addTheActionListeners(ActionListener theListener) {
        start.addActionListener(theListener);
    }

    public JButton getStart() {
        return start;
    }

    public void setBg(boolean shifter) {
        if(shifter) {
            this.setBackground(Color.red);
        } else {
            this.setBackground(Color.green);
        }
    }
}

CONTROLLER PANELONE

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import nwtrescontroller301.*;

public class PanOneController {
    PanOneView oneV;
    PanOneModel oneM;
    MainController main;

    public PanOneController(PanOneModel m, PanOneView v, MainController main_) {
        this.oneM = m;
        this.oneV = v;
        this.main = main_;
        oneV.addTheActionListeners(theListener);
    }

    public void run(boolean shift) {
        oneV.setBg(shift);
    }

    ActionListener theListener = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == oneV.getStart()) {
                main.start();
            }
        }
    };
}

PANELTWO VIEW

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class PanTwoView extends JPanel {

    JLabel jl = new JLabel("PANEL 2");
    JButton stop = new JButton("Stop");

    public PanTwoView() {
        this.setPreferredSize(new Dimension(100, 50));
        this.setBackground(Color.black);
        jl.setForeground(new java.awt.Color(255, 255, 255));
        add(jl);
        add(stop);
    }

    public void addTheActionListeners(ActionListener theListener) {
        stop.addActionListener(theListener);
    }

    public JPanel getPanelTwo() {
        return this;
    }

    public JButton getStop() {
        return stop;
    }

    public void setBg(boolean shift) {
        if(shift) {
            this.setBackground(Color.black);
        } else {
            this.setBackground(Color.blue);
        }
    }
}

PANELTWO CONTROLLER

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import nwtrescontroller301.*;

public class PanTwoController {
    PanTwoView twoV;
    PanTwoModel twoM;
    MainController mcon;

    public PanTwoController(PanTwoModel m, PanTwoView v, MainController mcon_) {
        this.twoV = v;
        this.twoM = m;
        this.mcon = mcon_;
        twoV.addTheActionListeners(theListener);
    }

    public void run(boolean shift) {
        twoV.setBg(shift);
    }

    ActionListener theListener = new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == twoV.getStop()) {
                mcon.stop();
                System.out.println("STOP");
            }
        }
    };
}
    
posta acroscene 10.11.2016 - 12:55
fonte

1 risposta

0

Especially regarding passing the MainController as an parameter to the constructor in the PanelOne and PanelTwo controllers

Eviterei sicuramente di farlo. Direi che PanOneController e PanTwoController (cioè i tuoi sottocontrolli) non dovrebbero essere consapevoli della presenza di MainController . Allo stesso modo, PanOneView e PanTwoView non dovrebbero essere a conoscenza dell'esistenza di MainView , sebbene questo non sia un problema nel tuo codice.

Rendendo conto di una vista secondaria o di un subcontroller della vista o controllore "genitore", sei severamente che limita la possibilità di riutilizzare quei componenti. Invece, consiglierei ai listener di notificare la gerarchia quando si verifica un'azione.

Guardando PanOneController e PanOneView , inizierei creando un'interfaccia PanOneViewListener che definirà i metodi che vengono chiamati in risposta a un'azione dell'utente. Tale interfaccia può quindi essere implementata da qualsiasi controller responsabile della logica di business dietro l'azione. La vista manterrà una collezione di questi listener che inviterà un'azione che viene eseguita.

Ad esempio:

public interface PanOneViewListener {
    public void onStartButtonClicked();
}

public class PanTwoView extends JPanel {
    private final List<PanOneViewListener> listeners = new ArrayList<PanOneViewListener>();

    public PanTwoView() {
        ...
        stop.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                notifyListenersOnStopButtonClicked();
            }
        });
        ...
    }

    private void notifyListenersOnStopButtonClicked() {
        for (final PanOneViewListener listener : listeners) {
            listener.onStartButtonClicked();
        }
    }

    public void addListener(final PanOneViewListener listener) {
        listeners.add(listener);
    }
}

public class PanOneController implements PanOneViewListener {
    public PanOneController(final PanOneModel m, final PanOneView v) {
        ...
        oneV.addListener(this);
        ...
    }
    ...
    @Override
    public void onStartButtonClicked() {
        // Respond to the button being clicked
    }
    ...
}

Nel tuo codice MainController ha la responsabilità di gestire il thread. Quindi, per rimuovere la dipendenza di PanOneController su MainController , possiamo nuovamente creare un listener per PanOneController più o meno allo stesso modo di prima:

public interface PanOneControllerListener {
    public void onStartButtonClicked();
}

public class PanOneController implements PanOneViewListener {
    private final List<PanOneControllerListener> listeners = new ArrayList<PanOneControllerListener>();

    public void addListener(final PanOneControllerListener listener) {
        listeners.add(listener);
    }

    @Override
    public void onStartButtonClicked() {
        for (final PanOneControllerListener listener : listeners) {
            listener.onStartButtonClicked();
        }
    }
}

public class MainController implements Runnable, PanOneControllerListener {

    public MainController(final MainView x, final MainModel y) {
        ...
        oneC = new PanOneController(oneM, x.getPanelOne(), this);
        oneC.addListener(this);
        ...
    }

    @Override
    public void onStartButtonClicked() {
        synchronized (this) {
            if (!running) {
                thread = new Thread(this);
                thread.start();
            }
            running = true;
        }
    }
}

Questo stesso pattern può essere applicato anche a PanTwoView e PanTwoController .

Ora le viste e i controller non dipendono dalla vista principale e dal controller e possono essere riutilizzati facilmente. Se dovessi usare PanOneView / PanOneController da qualche altra parte, ti basterà che il genitore implementa l'ascoltatore del controller per rispondere alle azioni.

    
risposta data 14.11.2016 - 21:27
fonte

Leggi altre domande sui tag