zoukankan      html  css  js  c++  java
  • Java设计模式(四)——再谈观察者模式

    在本系列的上一篇文章中,我们讨论了JDK对于观察者模式的一套实现。今天我们将要从另一个角度来探索Tomcat中是如何利用观察者模式加载各个组件。不过今天的任务不是解释Tomcat,所以我会单独把重点抽象出来展现如何在一个实际利用中使用Observer。

    先谈一下我对观察者模式的理解。对于对象而言,观察似乎是一个主动的过程——多位观察者通过“观察”一个被观察对象状态的改变来触发一些自身的行为。是的,就设计模式来说,观察者设计的本质确实如此。可是,当引入到Java语言以后,这个“解空间”就似乎不那么“完美”了。你无法让你一个对象做到“主动”观察——轮询机制不属于今天的讨论范畴。所以,我以为称为监听器模式更加合理。

    下面提出一个设计方案作为“解空间”的指导。在被观察对象(Subject)中定义一个能够注册(register)观察者(Observer)的方法和一个能够通知(notify)观察者的方法,观察者中定义一个被调用(update)的接口。

    代码1.1 Subject接口:

    public interface Subject {
        void registerObserver(Observer ob);
    
        void removeObserver();
    
        void notifyObserver();
    }

    代码1.2 Observer接口

    public interface Observer {
        void update();
    }

    对接口定义完成以后实现业务逻辑,我们在Subject的实现中假设存在一个业务接口business,这个方法的目的是实现具体的业务逻辑并调用Observer.update。

    代码2.1 Observer实现:

    public class ConcerteObserver implements Observer {
    
        @Override
        public void update() {
            System.out.println("update");
        }
    
    }

    代码2.2 Subject实现:

    public class ConcreteSubject implements Subject {
        private Observer ob;
    
        @Override
        public void registerObserver(Observer ob) {
            this.ob = ob;
        }
    
        @Override
        public void removeObserver() {
            this.ob = null;
        }
    
        @Override
        public void notifyObserver() {
            ob.update();
        }
    
        public void business() {
            notifyObserver();
        }
    
    }

    以上就是观察模式的代码逻辑,不过在实际运用的时候通常不会如此简单。下面我们来看一个相对复杂例子:利用观察者模式监听一个具有生命周期组件的各个状态。先解释一下什么是生命周期组件。在大型业务中,许多抽象的业务逻辑都具有生命周期状态。如新建、初始化、启动和停止等。不同的状态应该通知观察者触发不同的处理行为。

    代码3.1 Lifecycle接口

    public interface Lifecycle {
        public static final int NEW_EVENT = 0;
        public static final int INIT_EVENT = 1;
        public static final int START_EVENT = 2;
        public static final int STOP_EVENT = 3;
    
        void addListener(LifecycleListener listener);
        
        void removeListener(LifecycleListener listener);
        
        void fireLifecycleEvent(LifecycleState state);
    }

    Lifecycle接口提供给被观察对象实现,其中定义了4种状态事件。

    代码3.2 LifecycleState枚举类

    public enum LifecycleState {
        NEW(Lifecycle.NEW_EVENT), INIT(Lifecycle.INIT_EVENT), START(Lifecycle.START_EVENT), STOP(Lifecycle.STOP_EVENT);
    
        private final int triggerEvent;
    
        private LifecycleState(int triggerEvent) {
            this.triggerEvent = triggerEvent;
        }
    
        public int getTriggerEvent() {
            return triggerEvent;
        }
    
    }

    LifecycleState是一个枚举对象,用来约束不同的生命周期状态应该对应的事件。

    代码3.3 LifecycleListener接口

    public interface LifecycleListener {
        void lifecycleEvent(LifecycleState state);
    }

    观察者的触发接口,根据LifecycleState状态实现自定义业务

    代码3.4 LifeCycleBean类

    public class LifeCycleBean implements Lifecycle {
        private List<LifecycleListener> listeners = new ArrayList<>();
        private Object locked = new Object();
    
        @Override
        public void addListener(LifecycleListener listener) {
            synchronized (locked) {
                listeners.add(listener);
            }
        }
    
        @Override
        public void removeListener(LifecycleListener listener) {
            synchronized (locked) {
                listeners.remove(listener);
            }
        }
    
        @Override
        public synchronized void fireLifecycleEvent(LifecycleState state) {
            for (LifecycleListener listener : listeners) {
                listener.lifecycleEvent(state);
            }
        }
    
    }

    LifeCycleBean中我们已经实现了多行程下的调用,好处是将业务逻辑和代码设计进一步分离。

    代码3.5 StandardBusiness标准业务类

    public class StandardBusiness extends LifeCycleBean {
        private LifecycleState state = LifecycleState.NEW;
    
        public void process() {
            if (state.equals(LifecycleState.NEW)) {
                state = LifecycleState.INIT;
                fireLifecycleEvent(state);
            } else if (state.equals(LifecycleState.INIT)) {
                state = LifecycleState.START;
                fireLifecycleEvent(state);
            } else if (state.equals(LifecycleState.START)) {
                state = LifecycleState.STOP;
                fireLifecycleEvent(state);
            } else {
                System.out.println("process end");
            }
        }
    }

    在这段业务逻辑中多次调用process方法,可以模拟生命周期的不同阶段。

    代码3.6.1 InitListener类

    public class InitListener implements LifecycleListener {
    
        @Override
        public void lifecycleEvent(LifecycleState state) {
            if(state.getTriggerEvent() == Lifecycle.INIT_EVENT) {
                System.out.println("InitListener >> INIT_EVENT");
            }
        }
    
    }

    代码3.6.2 StartListener类

    public class StartListener implements LifecycleListener {
    
        @Override
        public void lifecycleEvent(LifecycleState state) {
            if (state.getTriggerEvent() == Lifecycle.START_EVENT) {
                System.out.println("StartListener >> START_EVENT");
            }
        }
    
    }

    代码3.6.3 StopListener类

    public class StopListener implements LifecycleListener {
    
        @Override
        public void lifecycleEvent(LifecycleState state) {
            if (state.getTriggerEvent() == Lifecycle.STOP_EVENT) {
                System.out.println("StopListener >> STOP_EVENT");
            }
        }
    
    }

    代码3.7 测试

    public class AppTest {
        @Test
        public void test() {
            StandardBusiness business = new StandardBusiness();
            business.addListener(new InitListener());
            business.addListener(new StartListener());
            business.addListener(new StopListener());
    
            business.process();
            business.process();
            business.process();
            business.process();
        }
    }

    总结:第二个例子逻辑相对复杂但是如果能够理清思路其实与第一个例子并无太大区别。而这个就是Tomcat中对于观察者模式的运用。

  • 相关阅读:
    将字典或者数组转换成JSON数据或者字符串
    [翻译] VICMAImageView
    [翻译] TransitionKit
    [翻译] UIGlossyButton
    [翻译] MMMaterialDesignSpinner
    [翻译] AFSoundManager
    实现UIView的无限旋转动画(非CALayer动画)
    【转】Winform 去掉 最大化 最小化 关闭按钮(不是关闭按钮变灰)终极解决办法
    【转】C# winform 安装程序打包(自定义操作)
    【转】C#安装包(自动卸载低版本)
  • 原文地址:https://www.cnblogs.com/learnhow/p/7707940.html
Copyright © 2011-2022 走看看