Страницы

Поиск по вопросам

четверг, 30 мая 2019 г.

В чем преимущества выделения контроллера в mvc?

У меня сразу несколько вопросов по mvc. Спрашивать буду на примере игрушечной программки, которую специально для этого написал:
public class View implements Observer {
private Model model; private IController controller;
private JLabel firstNumber = new JLabel(); private JLabel secondNumber = new JLabel(); private JLabel resultLabel = new JLabel();
public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { Model model = new Model(); IController controller = new Controller(); View view = new View(); view.setModel(model); view.setController(controller); view.createAndShowGUI(); } }); }
public void setModel(Model model) { this.model = model; model.addObserver(this); }
public void setController(IController controller) { this.controller = controller; }
public void createAndShowGUI() { JFrame frame = new JFrame("mvc train"); frame.setSize(400, 400); frame.getContentPane().add(createMainPanel()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }
private Component createMainPanel() { JPanel mainPanel = new JPanel(); mainPanel.add(firstNumber); mainPanel.add(secondNumber); mainPanel.add(resultLabel); JButton inc1 = new JButton("increment first"); inc1.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) { controller.execute("inc1", model); } }); JButton dec1 = new JButton("decrement first"); dec1.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) { controller.execute("dec1", model); } }); mainPanel.add(inc1); mainPanel.add(dec1); JButton inc2 = new JButton("increment second"); inc2.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) { controller.execute("inc2", model); } }); JButton dec2 = new JButton("decrement second"); dec2.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) { controller.execute("dec2", model); } }); mainPanel.add(inc2); mainPanel.add(dec2); return mainPanel; }
@Override public void update(Observable arg0, Object arg1) { firstNumber.setText("" + model.getA()); secondNumber.setText("" + model.getB()); resultLabel.setText("" + (model.getA() + model.getB())); }
}
Это класс представления. Получается такая картинка:
Кнопка increment first увеличивает на единицу первое число, increment second - второе, decrement first уменьшает первое число на единицу, decrement secomd - второе. В общем, после двух нажатий на increment first и одного нажатия на increment second получаем такую картинку:

Два числа хранятся в модели. Вот она:
public class Model extends Observable {
private int a; private int b;
public void incrementA() { a++; setChanged(); notifyObservers(); }
public void incrementB() { b++; setChanged(); notifyObservers(); }
public void decrementA() { a--; setChanged(); notifyObservers(); }
public void decrementB() { b--; setChanged(); notifyObservers(); }
public int getA() { return a; }
public int getB() { return b; }
@Override public void addObserver(Observer observer) { super.addObserver(observer); setChanged(); notifyObservers(); }
}
Мой контроллер:
public class Controller implements IController {
@Override public void execute(String action, Model model) { switch (action) { case "inc1": model.incrementA(); break; case "inc2": model.incrementB(); break; case "dec1": model.decrementA(); break; case "dec2": model.decrementB(); } }
}
Теперь вопросы. Самый главный вопрос собственно в названии.
Чем нам помог контроллер? Код из веток case оператора switch в контроллере мог бы с таким же успехом находится в слушателях. На каждую ветку по слушателю. В итоге слушателей все равно приходится создавать, что бы вызвать метод контроллера. А потом в этом методе в операторе switch прописывать тот же самой код, что мог бы быть в слушателях. Может быть я вообще неправильно реализовал mvc? Подозреваю что именно так. Причем именно в части контроллера. Потому что по нему в сети мало информации. Если это так то прошу подсказать как правильно. Слышал что можно создавать контроллеры для каждого элемента (в данном случае для каждой кнопки). Но ситуация не сильно поменяется. В моем примере все методы, которые вызывается в ветках case не имеют параметров. В реальных программах это скорее всего будет не так. Некоторые кнопки могли бы требовать вызовов методов с параметрами, причем с разным количеством параметров. Что делать в такой ситуации? Где лучше вычислять самое правое число? В моем примере я делаю это в функции update(). Не лучше ли это делать в модели?


Ответ

Контроллер помогает структурировать код. Весь код, реагирующий на пользовательский ввод, принадлежит контроллеру.
Можно было бы всё слить в один класс, и делать всю логику в OnClick, и код получился бы наверное даже короче. Но вашей целью должен быть не самый короткий, а самый понятный и легко поддерживаемый код. Мне кажется, ваша диспетчеризация команд по строкам — неправильна. Команды должны быть не строками, а объектами. (У нас же ООП, в конце-концов, да?) И вместо длинного свитча у вас должен быть всего лишь вызов Invoke. [Но это практика из MVVM, общепринятого паттерна в WPF, а традиции в MVC могут быть и другими.] Вычисления принадлежат модели и только ей. Представление должно не выполнять работу модели (а сложение в реальной программе превратится в серьёзное, длинное вычисление), а лишь только отображать её.

Комментариев нет:

Отправить комментарий