Java MVC模型,用于使用注释的大规模GUI

问题描述 投票:0回答:0

我正在尝试使用注释创建一个好的MVC模型,我将在大型GUI项目中使用它。 我想尊重最多的规则和指南,并且能够去除MVC的每个部分。 代码必须美观,可测试和可维护。 我写了一个示例项目来向您展示我的模型,您如何看待它? 不要温柔哈哈

启动器:

package example;

import javax.swing.SwingUtilities;

/**
 * Test class.
 * 
 * @author AwaX
 * @date Feb 10, 2015
 */
public class Example_MVC {

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

            @Override
            public void run () {
                final Model model = new Model();
                final Controller controller = new Controller(model);
                controller.showGui();
            }
        });
    }
}

数据模型:

package example;

import java.util.Observable;

/**
 * Data model.
 * 
 * @author AwaX
 * @date Feb 10, 2015
 */
public class Model extends Observable {

    private int counter;

    /**
     * Instanciate a default data model.
     */
    public Model () {
        super();
        this.counter = 0;
    }

    /**
     * Notify data model observers with new update.
     * 
     * @param arg
     *            Allow to specify a parameter for the observer.
     */
    public final void notifyChanged (Object... arg) {
        setChanged();
        if (arg.length == 0) {
            notifyObservers();
        } else if (arg.length == 1 && arg[0] != null) {
            notifyObservers(arg[0]);
        } else {
            throw new IllegalArgumentException("Only one argument allowed");
        }
        clearChanged();
    }

    public void inc () {
        this.counter++;
        notifyChanged(this.counter);
    }

    public int getCounter () {
        return counter;
    }

    public void setCounter (int c) {
        this.counter = c;
        notifyChanged(this.counter);
    }
}

控制者:

package example;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import example.View.ActionCallback;

/**
 * UI controller.
 * 
 * @author AwaX
 * @date Feb 10, 2015
 */
public class Controller {

    private final Model model;
    private final View view;
    private final ScheduledExecutorService scheduler;

    /**
     * Instanciate the controller.
     * 
     * @param model
     *            Data model.
     */
    public Controller (final Model model) {
        this.model = model;
        this.view = new View(model);
        this.view.addListener(this);
        this.model.addObserver(this.view);
        this.scheduler = Executors.newScheduledThreadPool(1);
        this.scheduler.scheduleAtFixedRate(new IncrementTask(), 0, 1000, TimeUnit.MILLISECONDS);
    }

    /**
     * Show the GUI.
     */
    public void showGui () {
        this.view.showGui();
    }

    @ActionCallback (event = "action1")
    public void action1 () {
        System.out.println("# Action 1");
    }

    @ActionCallback (event = "action2")
    public void action2 () {
        System.out.println("# Action 2");
    }

    /**
     * Increment the data model periodically.
     * 
     * @author AwaX
     * @date Feb 10, 2015
     */
    private class IncrementTask implements Runnable {

        @Override
        public void run () {
            model.inc();
        }
    }
}

风景 :

package example;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;

/**
 * User interface.
 * 
 * @author AwaX
 * @date Feb 10, 2015
 */
public class View extends JFrame implements Observer {

    private static final long serialVersionUID = 4240474354742402647L;

    @Retention (RetentionPolicy.RUNTIME)
    @Target (ElementType.METHOD)
    public @interface ActionCallback {
        String event();
    }

    private final ArrayList<Object> listeners;

    private JButton btn1;
    private JButton btn2;
    private JTextField tf;

    /**
     * Instanciate the user interface.
     * 
     * @param model
     *            Data model.
     */
    public View (final Model model) {
        super("MVC Example");
        this.listeners = new ArrayList<>();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        createGui();
    }

    /**
     * Show the GUI.
     */
    public void showGui () {
        setMinimumSize(new Dimension(300, 200));
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    /**
     * Allow an object to subscribe for UI events.
     * 
     * @param o
     *            The subscriber object.
     */
    public void addListener (Object o) {
        if (!this.listeners.contains(o)) {
            this.listeners.add(o);
        }
    }

    /**
     * Create the GUI and add listeners.
     */
    private void createGui () {
        this.btn1 = new JButton("Button 1");
        this.btn2 = new JButton("Button 2");
        this.tf = new JTextField();

        setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
        add(this.btn1);
        add(this.btn2);
        add(this.tf);

        this.btn1.setAction(new ButtonAction("action1"));
        this.btn2.setAction(new ButtonAction("action2"));
    }

    @Override
    public void update (Observable o, Object arg) {
        if (o instanceof Model) {
            Model model = (Model) o;
            this.tf.setText("" + model.getCounter());
        }
    }

    /**
     * Listener on button actions.
     * 
     * @author AwaX
     * @date Feb 10, 2015
     */
    private class ButtonAction extends AbstractAction {

        private static final long serialVersionUID = 9077483825287720181L;

        public ButtonAction (final String name) {
            super(name);
        }

        @Override
        public void actionPerformed (ActionEvent e) {
            for (Object o : listeners) {
                for (Method m : o.getClass().getMethods()) {
                    for (Annotation a : m.getAnnotations()) {
                        if (a instanceof ActionCallback) {
                            ActionCallback callback = (ActionCallback) a;
                            if (callback.event().equals(e.getActionCommand())) {
                                try {
                                    m.invoke(o);
                                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
                                    e1.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
java user-interface model-view-controller reflection
© www.soinside.com 2019 - 2024. All rights reserved.