Что такое контроллер в Java Swing? - PullRequest
12 голосов
/ 29 апреля 2011

Я хотел бы применить дизайн MVC к моему Java-приложению, используя Swing осмысленным способом.Поэтому мой вопрос, как контроллеры будут структурированы в Java Swing?

Я имею в виду две опции:

  1. Каждый компонентный слушатель является собственным классом, как часть контроллераpackage
  2. Каждый слушатель компонентов является анонимным классом внутри пакета представления, который делегирует свой вызов классу с методами контроллера.

Возможно ли и то и другое?Это вопрос предпочтения или он четко определен?

Ответы [ 7 ]

23 голосов
/ 29 апреля 2011

Контроллер составляет вторую половину интерфейса компонента, в основном половину взаимодействия.Контроллер заботится о событиях мыши и клавиатуры.

в таких компонентах Swing, как JButton и т. Д., Являются контроллерами.и все классы слушателей перенаправляют события в модель с вашей бизнес-логикой

пример:

основная программа

import javax.swing.*;

public class CalcMVC {
    //... Create model, view, and controller.  They are
    //    created once here and passed to the parts that
    //    need them so there is only one copy of each.
    public static void main(String[] args) {

        CalcModel      model      = new CalcModel();
        CalcView       view       = new CalcView(model);
        CalcController controller = new CalcController(model, view);

        view.setVisible(true);
    }
}

Просмотр

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

class CalcView extends JFrame {
    //... Constants
    private static final String INITIAL_VALUE = "1";

    //... Components
    private JTextField m_userInputTf = new JTextField(5);
    private JTextField m_totalTf     = new JTextField(20);
    private JButton    m_multiplyBtn = new JButton("Multiply");
    private JButton    m_clearBtn    = new JButton("Clear");

    private CalcModel m_model;

    //======================================================= constructor
    /** Constructor */
    CalcView(CalcModel model) {
        //... Set up the logic
        m_model = model;
        m_model.setValue(INITIAL_VALUE);

        //... Initialize components
        m_totalTf.setText(m_model.getValue());
        m_totalTf.setEditable(false);

        //... Layout the components.      
        JPanel content = new JPanel();
        content.setLayout(new FlowLayout());
        content.add(new JLabel("Input"));
        content.add(m_userInputTf);
        content.add(m_multiplyBtn);
        content.add(new JLabel("Total"));
        content.add(m_totalTf);
        content.add(m_clearBtn);

        //... finalize layout
        this.setContentPane(content);
        this.pack();

        this.setTitle("Simple Calc - MVC");
        // The window closing event should probably be passed to the 
        // Controller in a real program, but this is a short example.
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    void reset() {
        m_totalTf.setText(INITIAL_VALUE);
    }

    String getUserInput() {
        return m_userInputTf.getText();
    }

    void setTotal(String newTotal) {
        m_totalTf.setText(newTotal);
    }

    void showError(String errMessage) {
        JOptionPane.showMessageDialog(this, errMessage);
    }

    void addMultiplyListener(ActionListener mal) {
        m_multiplyBtn.addActionListener(mal);
    }

    void addClearListener(ActionListener cal) {
        m_clearBtn.addActionListener(cal);
    }
}

контроллер

import java.awt.event.*;

public class CalcController {
    //... The Controller needs to interact with both the Model and View.
    private CalcModel m_model;
    private CalcView  m_view;

    //========================================================== constructor
    /** Constructor */
    CalcController(CalcModel model, CalcView view) {
        m_model = model;
        m_view  = view;

        //... Add listeners to the view.
        view.addMultiplyListener(new MultiplyListener());
        view.addClearListener(new ClearListener());
    }


    ////////////////////////////////////////// inner class MultiplyListener
    /** When a mulitplication is requested.
     *  1. Get the user input number from the View.
     *  2. Call the model to mulitply by this number.
     *  3. Get the result from the Model.
     *  4. Tell the View to display the result.
     * If there was an error, tell the View to display it.
     */
    class MultiplyListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            String userInput = "";
            try {
                userInput = m_view.getUserInput();
                m_model.multiplyBy(userInput);
                m_view.setTotal(m_model.getValue());

            } catch (NumberFormatException nfex) {
                m_view.showError("Bad input: '" + userInput + "'");
            }
        }
    }//end inner class MultiplyListener


    //////////////////////////////////////////// inner class ClearListener
    /**  1. Reset model.
     *   2. Reset View.
     */    
    class ClearListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            m_model.reset();
            m_view.reset();
        }
    }// end inner class ClearListener
}

Модель

import java.math.BigInteger;

public class CalcModel {
    //... Constants
    private static final String INITIAL_VALUE = "0";

    //... Member variable defining state of calculator.
    private BigInteger m_total;  // The total current value state.

    //============================================================== constructor
    /** Constructor */
    CalcModel() {
        reset();
    }

    //==================================================================== reset
    /** Reset to initial value. */
    public void reset() {
        m_total = new BigInteger(INITIAL_VALUE);
    }

    //=============================================================== multiplyBy
    /** Multiply current total by a number.
    *@param operand Number (as string) to multiply total by.
    */
    public void multiplyBy(String operand) {
        m_total = m_total.multiply(new BigInteger(operand));
    }

    //================================================================= setValue
    /** Set the total value. 
    *@param value New value that should be used for the calculator total. 
    */
    public void setValue(String value) {
        m_total = new BigInteger(value);
    }

    //================================================================= getValue
    /** Return current calculator total. */
    public String getValue() {
        return m_total.toString();
    }
}
8 голосов
/ 29 апреля 2011

Platzhirsch,

Чувак, это СЕРЬЕЗНО тяжелый вопрос ... на который никто не собирается адекватно ответить в сообщении на форуме.Этот artice Разработка приложений Java SE С MVC от Роберт Экштейн (один из богов Java) подробно обсуждает эту проблему.«вариант» MVC, который я назвал MBVC (Model Business View Controller), который на самом деле очень близок к MVVMC ... MVVM широко используется в кругах .NET;добавление контроллера имело смысл для меня, так как у меня был некоторый опыт работы с MVC.Хотелось бы, чтобы я прочитал вышеупомянутую статью ПРЕЖДЕ ЧЕМ я настроил MVC-приложение для моего приложения.Вы все еще можете прочитать мои довольно озадаченные посты на форумах Sun (ныне Oracle) по Java.

Приветствия.Кит.

4 голосов
/ 29 апреля 2011

Хотя среда Swing уже реализует форму MVC (явные модели; классы JXyz и UI = контроллер и представление), это строгое разделение редко используется на уровне приложений и выглядит довольно странно.

Для начала предлагаю придерживаться следующего дизайна:

  • реализовать бизнес-логику на стороне клиента с помощью POJO
  • Оберните POJO пользовательскими моделями Swing, где это необходимо (ListModel, TableModel)
  • Используйте конструктор GUI для разработки GUI
  • Использование шаблона Mediator для прослушивания событий (пользовательский родительский JPanel прослушивает события своих дочерних элементов и обновляет других дочерних элементов или запускает собственные события при необходимости)

Если вы хотите пойти дальше, используйте RCP, например, платформу NetBeans (очень рекомендуется).

2 голосов
/ 29 апреля 2011

Посмотрите это Архитектура MVC

1 голос
/ 29 апреля 2011

Представление будет охватывать дизайн GUI.Метод actionPerformed представления должен идентифицировать событие и вызывать соответствующие методы на ControllerInterface в зависимости от события.Реализация контроллера будет реализовывать этот ControllerInterface, и методы, которые вызываются представлением, будут реализованы здесь.Эти методы предположительно будут взаимодействовать с моделью в некотором роде.Сама модель будет иметь возможность регистрировать наблюдателей (в данном случае представление; между прочим, даже контроллеры могут быть зарегистрированы) и обновлять наблюдателей каждый раз, когда модель изменяется.По сути, именно так вы бы структурировали свое приложение.Для получения более подробной информации о MVC, вы также можете обратиться: здесь!

0 голосов
/ 29 апреля 2011

Для четкого разделения View и Controller вы можете сделать это следующим образом:

public class MyView extends SomeSwingComponent {

   private Controller controller;
   public View(Controller controller) {
     this.controller = controller;
     JButton saveButton = new JButton("Save");
     button.addActionListner(controller.getSaveButtonListener());
   }
}

public class MyController implements Controller {
  private ActionListener saveButtonListener;
  @Override
  public ActionListener getSaveButtonListener() {
    if (saveButtonListener == null) {
      saveButtonListener = new ActionListener() {
        // ...
      }
  }
}

Теперь мы можем реализовать разные контроллеры, что может быть удобно, если мы хотим использовать компонент вида с разными моделями. Контроллер является стратегией фактического экземпляра представления.

В большинстве случаев достаточно просто определить слушателей как анонимные классы, потому что они обычно просто вызывают метод на экземпляре контроллера. Я обычно использую слушателей как простых диспетчеров - они получают уведомление и отправляют сообщение другому объекту. Класс слушателя должен реализовывать слишком много бизнес-логики, что выходит за рамки его ответственности.

0 голосов
/ 29 апреля 2011

Я имею в виду две опции:

  1. Каждый слушатель компонентов является собственным классом, как часть пакета контроллера
  2. Каждый слушатель компонентов является анонимным классом внутрипакет представления, который делегирует свой вызов классу с методами контроллера.Возможно ли и то и другое?

Да возможно и то и другое, но я предпочту написать Single класс, реализующий все actionListionerи назначьте то же самое для всех компонентов в вашем приложении.Таким образом, вы можете отслеживать все действия в вашем приложении в одной точке.Также таким образом вы можете отличить ваш взгляд от контроллера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...