Страницы

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

понедельник, 9 марта 2020 г.

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

#java #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().
Не лучше ли это делать в модели?

    


Ответы

Ответ 1



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

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

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