Анализ шаблона проектирования-1: шаблон наблюдателя

Java Шаблоны проектирования Android UML

1. Обратный вызов интерфейса

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

так называемыйобратный вызов интерфейсаОбщая ситуация с приложением такова: вы не знаете, когда метод вернется, но хотите получить результат выполнения метода, когда метод завершится. Обычно, например, поток запускается внутри метода, и мы хотим получить результат выполнения потока, когда выполнение потока завершится.

В приведенном ниже примере методcal()Я определяю локальную переменную, затем открываю поток и меняю значение i при выполнении потока. Мы надеемся достичь результатов, когда поток будет завершен.

    public int cal() {
        int i;
        new Thread(new Runnable() { 
            Thread.sleep(3000); // throw ... ignore it
            i++; 
        }).start();
        return i;
    }

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

Мы можем решить эту проблему, используя обратные вызовы интерфейса. Мы можем передать экземпляр интерфейса обратного вызова при вызове этого метода. После выполнения всей логики в потоке мы используем интерфейсcall()Метод вызывает обратно i out:

    public void cal(Callback callback) {
        int i;
        new Thread(new Runnable() { 
            Thread.sleep(3000); // throw ... ignore it
            i++; 
            if (callback != null) {
                callback.call(i); // 1
            }
        }).start();
    }

Конечно, обратный вызов интерфейса больше похож на преобразование моегоcall()Метод внедряется в 1 место в приведенном выше коде. Это приближается к концепции так называемого функционального программирования, когда интерфейс внедряется в метод как функцию.

Существуют очень богатые сценарии приложений для обратного вызова интерфейса, как правило, некоторые асинхронные сценарии, такие как «прослушивание» результата выполнения кнопки и т. д.

2. Режим наблюдателя

Что ж, разобравшись с обратным вызовом интерфейса выше, давайте взглянем на шаблон Observer. Во-первых, давайте рассмотрим некоторые концепции шаблона проектирования Observer.

Используя пример в 1 в качестве аналогии, тогда я нашТема, вызывается класс, в котором мы выполняем обратный вызов интерфейса (класс, в котором реализованный обратный вызов передается методу cal).Наблюдатель (подписчик).

观察者模式UML

Вышеуказанный режим наблюдателяUML-модель. здесьSubjectИнтерфейс — это интерфейс субъекта, аConcreteSubkectявляется его конкретным классом реализации, то есть конкретным субъектом.ObserverИнтерфейс — это интерфейс наблюдателя,ConcreteObserverявляется конкретным наблюдателем. Тема часто поддерживает ряд наблюдателей через список, а затем упрощает этот список, чтобы уведомить всех наблюдателей об изменении темы. Итак, вотSubjectИнтерфейс определяет три метода, сверху вниз, используемые для добавления наблюдателей в тему, удаления наблюдателей из темы и уведомления всех наблюдателей об обновлениях темы.

Ниже мы приводим код простейшего шаблона проектирования наблюдателя:

1. Первое – это определение предмета:

    public class ConcreteSubject implements Subject {

        // 通过队列维护观察者列表
        private List<Observer> observers = new LinkedList<>();

        // 注册一个观察者
        @Override
        public void registerObserver(Observer o) {
            observers.add(o);
        }

        // 移除一个观察者
        @Override
        public void removeObserver(Observer o) {
            int i = observers.indexOf(o);
            if (i >= 0) {
                observers.remove(o);
            } 
        }

        // 通知所有观察者主题的更新
        @Override
        public void notifyObservers() {
            for (Observer o : observers) {
                o.method();
            }
        }
    }

2. Далее идет определение класса наблюдателя:

    public class ConcreteObserver implements Observer {
        
        // 该观察者订阅的主题
        private Subject subject;

        public ConcreteObserver(Subject subject) {
            this.subject = subject;
            // 将当前观察者添加到主题订阅列表中
            subject.registerObserver(this);
        }
        
        // 当主题发生变化的时候,主题会遍历观察者列表并通过调用该方法来通知观察者
        @Override
        public void method() {
            // ...  
        }
    }

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

3. Резюме

Наблюдатель и наблюдаемое слабо связаны и абстрактно связаны, поэтому для обоих легче расширяться.

Шаблон наблюдателя — это широко используемый механизм триггера, который формирует цепочку триггеров и по очереди обрабатывает методы каждого наблюдателя. Но в то же время это и недостаток режима наблюдателя, так как это цепной триггер, когда наблюдателей много, проблема производительности больше беспокоит. Более того, в цепной структуре она более подвержена циклическим ошибкам ссылок, что приводит к приостановке анимации системы. И поскольку ссылка на наблюдателей сохраняется в списке наблюдателей, когда они не освобождаются вовремя, это может вызвать утечку памяти.