美文网首页
观察者模式

观察者模式

作者: 奋斗的韭菜汪 | 来源:发表于2020-06-23 17:23 被阅读0次

    生活中的场景:微信红点通知,手机起床闹钟
    使用场景:1、当一个抽象模型包含两个方面内容,其中一个方面依赖于另一个方面;
    2、其他一个或多个对象的变化依赖于另一个对象的变化
    3、实现类似广播机制的功能,无需知道具体收听者,只需分发广播,系统中感兴趣的对象会自动接收该广播;
    4、多层嵌套使用,形成一种链式触发机制,使得事件具备跨域(跨越两种观察者类型)通知
    标准代码结构:抽象主题,具体主题,抽象观察者,具体观察者
    具体主题(被观察者)会存储所有观察者,一旦主题发生变化,会逐一通知被观察者

    jdk实现观察者模式:被观察者 extends Observable,观察者implements Observer

    image.png
    这里实现了Observer jdk会自动将观察者加入Vector<Observer>集合
    例子:用户给社区老师提问的例子
    public class Community extends Observable {
        private String name = "社区";
        private static final Community instance = new Community();
        private Community(){}
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public static Community getInstance(){
            return instance;
        }
        public void publishQuestion(Question question){
            System.out.println(question.getUsername() + "在" + this.name + "提交了一个问题!");
            setChanged();
            notifyObservers(question);
        }
    }
    
    public class Question {
        private String username;
        private String content;
        public String getUsername() {
            return username;
        }
        public void setUsername(String username) {
            this.username = username;
        }
        public String getContent() {
            return content;
        }
        public void setContent(String content) {
            this.content = content;
        }
    }
    
    public class Teacher implements Observer {
        private String name;
        public Teacher(String name){
            this.name = name;
        }
        public void update(Observable o, Object arg) {
                Community community = (Community)o;
                Question question = (Question)arg;
            System.out.println("===============");
            System.out.println(name + "老师,你好\n" +
                    "您收到了一个来自" + community.getName() +
                    "的提问,希望您解答。问题内容为:" +
                    question.getContent() +"\n" +
                    "提问者:" + question.getUsername());
        }
    }
    
    public class Test {
    
        public static void main(String[] args) {
            Community community = Community.getInstance();
            Teacher tom = new Teacher("tom");
            Teacher lily = new Teacher("lily");
            community.addObserver(tom);
            community.addObserver(lily);
            Question question = new Question();
            question.setUsername("zhangsan");
            question.setContent("观察者模式使用场景是那些?");
            community.publishQuestion(question);
        }
    }
    

    运行结果

    zhangsan在社区提交了一个问题!
    ===============
    lily老师,你好
    您收到了一个来自社区的提问,希望您解答。问题内容为:观察者模式使用场景是那些?
    提问者:zhangsan
    ===============
    tom老师,你好
    您收到了一个来自社区的提问,希望您解答。问题内容为:观察者模式使用场景是那些?
    提问者:zhangsan
    
    Process finished with exit code 0
    

    谷歌guava实现观察者模式(常用):

        <dependencies>
            <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>18.0</version>
            </dependency>
        </dependencies>
    
    public class GuavaEvent {
        @Subscribe
        public  void observer1(Object o){
            System.out.println("执行observer1方法,传参为:" + o.toString());
        }
        @Subscribe
        public void observer2(Object o){
            System.out.println("执行observer2方法,传参为:" + o.toString());
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            //消息总线
            EventBus eventBus = new EventBus();
            GuavaEvent guavaEvent = new GuavaEvent();
            eventBus.register(guavaEvent);
    
            eventBus.post("nihao ");
        }
    }
    

    结果

    执行observer2方法,传参为:nihao 
    执行observer1方法,传参为:nihao 
    
    Process finished with exit code 0
    

    手写一个观察者模式,并模拟鼠标点击事件
    被观察者抽象

    public class EventListener {
        //存储被观察者map
        protected Map<String, Event> events = new HashMap<String, Event>(16);
        public void addListener(String eventType, Object target, Method callback){
            events.put(eventType, new Event(target,callback));
        }
        //如果没有回调
        public void addListener(String eventType, Object target){
            try {
                //约定Event方法名已on开头
                this.addListener(eventType, target, target.getClass().getMethod("on" + toUpperFirstCase(eventType), Event.class));
                //events.put(eventType, new Event(target,callback));
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        private String toUpperFirstCase(String eventType) {
            char[] chars = eventType.toCharArray();
            chars[0] -= 32;
            return String.valueOf(chars);
        }
        private void trigger(Event event){
            event.setSource(this);
            event.setTime(System.currentTimeMillis());
            try {
                if (event.getCallback() != null) {
                    //用反射调用函数
                    event.getCallback().invoke(event.getTarget(),event);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        protected void trigger(String trigger){
            if(!this.events.containsKey(trigger)){return;}
            trigger(this.events.get(trigger).setTrigger(trigger));
    
        }
    }
    

    具体被观察者

    public class Mouse extends EventListener{
    
        public void click(){
            System.out.println("调用单机方法");
            this.trigger(MouseEventType.ON_CLICK);
        }
    }
    
    public class MouseEventCallback {
        //update
        public void onClick(Event e){
            System.out.println("触发鼠标单击事件");
        }
    }
    
    public class Event {
        //事件源,动作是由谁发出的
        private Object source;
        //事件触发,要通知谁(观察者)
        private Object target;
        //观察者给的回应
        private Method callback;
        //事件的名称
        private String trigger;
        //事件的时间
        private long time;
    
        public Event(Object target, Method callback) {
            this.target = target;
            this.callback = callback;
        }
    
        public Object getSource() {
            return source;
        }
    
        public Event setSource(Object source) {
            this.source = source;
            return this;
        }
    
        public Object getTarget() {
            return target;
        }
    
        public Event setTarget(Object target) {
            this.target = target;
            return this;
        }
    
        public Method getCallback() {
            return callback;
        }
    
        public Event setCallback(Method callback) {
            this.callback = callback;
            return this;
        }
    
        public String getTrigger() {
            return trigger;
        }
    
        public Event setTrigger(String trigger) {
            this.trigger = trigger;
            return this;
        }
    
        public long getTime() {
            return time;
        }
    
        public Event setTime(long time) {
            this.time = time;
            return this;
        }
    
        @Override
        public String toString() {
            return "Event{" +
                    "source=" + source +
                    ", target=" + target +
                    ", callback=" + callback +
                    ", trigger='" + trigger + '\'' +
                    ", time=" + time +
                    '}';
        }
    }
    
    public interface MouseEventType {
        String ON_CLICK = "click";
    }
    
    public class Test {
        public static void main(String[] args) {
            //具体观察者
            MouseEventCallback callback = new MouseEventCallback();
            //被观察者
            Mouse mouse = new Mouse();
            mouse.addListener(MouseEventType.ON_CLICK, callback);
            mouse.click();
        }
    }
    

    运行结果:

    调用单机方法
    触发鼠标单击事件
    
    Process finished with exit code 0
    

    相关文章

      网友评论

          本文标题:观察者模式

          本文链接:https://www.haomeiwen.com/subject/nhkhfktx.html