• Шаблоны для вашего сайта
  • Сделать сайт
  • Реклама
  • Berry CSS
  • Albireo Framework
  • Бесплатный HTML-курс
  • Telegram-канал
  • Обратная связь
MaxSite.org
О создании сайтов и не только
Создание сайтов под ключ (Украина) →
Вход
×
или зарегистрироваться

Реализация паттерна Observer в MVC (Model View Controller) для JavaFX

Java и AndroidПросмотров: 7526Комментарии: 017 июля 2018 г.

В продолжении предыдущей статьи «MVC (Model View Controller) в JavaFX», я решил-таки реализовать паттерн Наблюдатель (Observer), чтобы довести работу до логического завершения. За основу я взял код Java с Википедии. Этот пример из книги «Паттерны проектирования» Эрика и Элизабет Фримен, поэтому наверняка все его разбирали.

Пример я немного упростил, поскольку «погодная станция» нам не нужна, а также сделал так, чтобы уведомления могли быть разными.

В конце статьи вы найдете исходные коды для загрузки.

В отличие от предыдущего варианта программы, я добавил ещё одну метку, которая показывает текущую операцию. Она демонстрирует работу второго оповещения.

Вид программы

Общее описание паттерна «Наблюдатель»

Есть некий объект, который выполняет роль наблюдателя (Observable). Слушатель (Observer) — это те объекты, которые регистрируются у наблюдателя. Наблюдатель отправляет уведомления всем слушателям. Те его получают и дальше уже сами решают что с ним делать.

В проекте создаётся файл Observer.java:

package org.maxsite;
/*
* Это интерфейы для организации паттерна Наблюдатель
* */
 
// слушатель
interface Observer {
    void notification(String message);
}
 
// наблюдатель
interface Observable {
    void registerObserver(Observer o);
    void notifyObservers(String message);
}

Это обычные интерфейсы, где у наблюдателя будут функции регистрации и уведомления, а у слушателей — функция, которая будет срабатывать при поступлении уведомления.

Model

Модель будет Наблюдателем.

package org.maxsite;
/*
* здесь вычисления и внутреннее хранение данных
* а также регистрация и уведомление слушателей
* */
 
import java.util.LinkedList;
import java.util.List;
 
class Model implements Observable {
 
    private List<Observer> observers; // список слушателей
 
    private String op = "-"; // операция
    private String num1 = "1"; // первое число
    private String num2 = "2"; // второе число
    private String result = "1-2"; // результат
 
    // конструктор: создаем новый список для слушателей
    Model() {
        observers = new LinkedList<>();
    }
 
    // регистрация слушателя
    @Override public void registerObserver(Observer o) {
        observers.add(o);
    }
 
    // уведомление слушателей
    @Override public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.notification(message);
        }
    }
 
    // выставляет операцию
    void setOp(String s) {
        op = s;
        notifyObservers("op");
    }
 
    // выставляет num1
    void setNum1(String s) {
        num1 = s;
    }
 
    // выставляет num2
    void setNum2(String s) {
        num2 = s;
    }
 
    // вычисляем результат
    void go() {
        result = num1 + op + num2;
        notifyObservers("go");
    }
 
    // отдаем результат
    String getResult() {
        return result;
    }
 
    String getOp() {
        return op;
    }
}

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

Уведомление рассылается с помощью notifyObservers() с параметром, где можно задать название сообщения. В этом варианте Модель может уведомить о нескольких событиях. В нашем случае идёт уведомление «go» при получении готового результата, и «op», когда меняется операция.

При этом Модель, опять же, ничего не знает о том, кто её использует.

Кто слушатель: View или Controller?

С ходу решить эту задачку у меня не получилось, поэтому пришлось повозиться. :-) Проблема в том, что для Контролёра в JavaFX мы не можем просто так вызвать конструктор. Это как-то связано с FXMLLoader, который сам его создает, а значит у нас нет возможности его переопределить, если она и есть (я не в курсе), то неясно насколько это окажется плохой идеей.

Можно было бы выделить класс Контролёра в main-файле и там уже зарегистрироваться в качестве слушателя, но мне такая идея не понравилась.

Поэтому в качестве слушателя может быть суперкласс View. При этом придется перенести в него создание Модели, иначе не получится зарегистрироваться. Соответственно Контролёр получает доступ к Модели автоматически, поскольку расширяет Представление.

View

Код View.java.

package org.maxsite;
/*
* это представление: то, что выводится на форму
* */
 
import javafx.fxml.FXML;
import javafx.scene.control.Label;
 
class View implements Observer {
 
    // поля вывода
    @FXML private Label LabelResult;
    @FXML private Label LabelOp;
 
    // создаем модель здесь, поскольку это суперкласс для контролера
    Model model = new Model();
 
    // конструктор: регистрация на сообщения модели
    View() {
        model.registerObserver(this);
    }
 
    // уведомления от модели
    @Override public void notification(String message) {
        // разные уведомления под разный вывод
        if (message.equals("go")) {
            this.displayLabel(model.getResult());
        }
        else if (message.equals("op")) {
            this.displayOp(model.getOp());
        }
    }
 
    // выводит текст в LabelResult (результат)
    private void displayLabel(String s){
        LabelResult.setText("Результат: " + s);
    }
 
    // выводит текст в LabelOp (операция)
    private void displayOp(String s) {
        LabelOp.setText("Операция: " + s);
    }
}

Регистрация в качестве слушателя происходит автоматически в конструкторе. При получении уведомления (функция notification()), выполняется либо вывод результата, либо вывод операции. Такое разделение позволяет без проблем добавить любой другой вывод на форму.

Controller

Теперь файл Controller.java.

package org.maxsite;
/*
* это контролер, он жестко завязан на форму
* */
 
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
 
public class Controller extends View {
 
    // форма: поля ввода
    @FXML private TextField tf1;
    @FXML private TextField tf2;
 
    // контролер знает модель из View
 
    // нажатите кнопки BtnPlus
    @FXML public void onActionBtnPlus() {
        model.setOp("+");
    }
 
    // нажатите кнопки BtnMinus
    @FXML public void onActionBtnMinus() {
        model.setOp("-");
    }
 
    // нажатите кнопки BtnGo - получение результата
    @FXML public void onActionBtnGo() {
        this.go();
    }
 
    // функция для получения и вывода результата
    private void go() {
        // отдаем модели нужные данные
        model.setNum1(tf1.getText());
        model.setNum2(tf2.getText());
 
        // вычисляем результат
        model.go();
    }
}

Он стал ещё проще. За получение результата теперь отвечает Модель, которая автоматом доступна из View. То есть Контролёр только отправляет Модели данные при получении событий с кнопок.

Код достаточно простой, да ещё и с комментариями, поэтому добавить больше нечего.

Желающие могут скачать исходные файлы.


Создание сайтов (Украина) →
Верстка с помощью CSS Grid Layout
MVC (Model View Controller) в JavaFX
twitter.com facebook.com
Другие записи сайта
Обработка форм в PHP. Как это делать правильно в 2020 году
Обработка форм в PHP. Как это делать правильно в 2020 году
Самая сложная задача в лендинге
Самая сложная задача в лендинге
Адаптивная сетка. Верстка по-новому
Адаптивная сетка. Верстка по-новому
Как обновить Open Server Panel
Как обновить Open Server Panel
Матрица: Воскрешение / The Matrix Resurrections (2021)
Матрица: Воскрешение / The Matrix Resurrections (2021)
Шаблон Strategy (Стратегия)
Шаблон Strategy (Стратегия)
Оставьте комментарий!

Комментарий будет опубликован после проверки. Вы соглашаетесь с правилами сайта.

(обязательно)

Навигация
  • Шаблоны для MaxSite CMS 22
  • jQuery и JavaScript 6
  • Java и Android 5
  • PHP/ООП 25
  • SQL 17
  • Albireo Framework 11
  • Berry CSS 7
  • CSS, HTML, LESS, SASS 23
  • PHP 37
  • Тайм-менеджмент 9
  • Софт 37
  • SEO 13
  • Git. GitHub 3
  • CodeIgniter 5
  • Landing Page 3
  • Alpine.js 14
  • Фильмы 2
  • Дневник 55

Здесь можно заказать создание сайта (только Украина), шаблона или лендинга. Также вы можете выбрать готовые шаблоны для MaxSite CMS по небольшой цене. Также можно купить отдельные модули, компоненты для вашего сайта.

MaxSite.org
Как создать свой сайт

Услуги по созданию сайтов, блогов, лендингов
Обратная связь • Реклама на сайте
Карта сайта
Мои проекты
  • Шаблоны для вашего сайта
  • Заказать создание сайта
  • MaxSite CMS
  • Berry CSS (CSS Utilities)
  • Albireo Framework
  • UniCSS (Universal Atomic CSS)
  • Landing Page Framework
  • Бесплатные НТML-курсы
Ссылки
  • Telegram-канал
  • Github
  • Twitter
  • Telegram-бот
  • RSS
© MaxSite.org, 2006-2022. Работает на MaxSite CMS | Время: 0.2810 | SQL: 20 | Память: 4.61MB | Вход