美文网首页程序员Java设计模式技术干货
设计模式——观察者者模式

设计模式——观察者者模式

作者: BrightLoong | 来源:发表于2018-05-27 21:34 被阅读20次
    builder
    阅读原文请访问我的博客BrightLoong's Blog

    一. 概述

    观察者模式(Observer) ,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。

    观察者模式,不论实现方式如何,需要具备最基本的Subject(被观察的主题)、Observer(观察者),最后就是试用它们的Client(客户端)。

    观察者模式属于行为型模式。

    二. UML类图解析

    builder
    • Subject:被观察的主题,可以是一个抽象类或者接口,它把所有对观察者对象的引用保存在一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供增加和移除观察者对象的方法。
    • Observer:抽象观察者,可以是一个抽象类或者接口,定义了一个update方法,在得到主题的通知时进行更新。
    • ConcreteObserverA、ConcreteObserverB:具体的观察者,实现观察者接口。
    • ConcreteSubject:具体主题,继承Subject,保存主题相关的一些状态。

    三. 代码实现

    打仗的时候,当哨兵观察到敌方来袭会通知所有士兵做好迎敌准备,士兵得到通知和进行准备。这里把哨兵通知当成一个主题,其他士兵(弓兵、骑兵、步兵等)在接到通知的时候作出相应的准备。

    观察者接口——Soldier

    package io.github.brightloong.design.observer;
    
    /**
     * Created by BrightLoong on 2018/5/27.
     */
    public interface Soldier {
        //视具体情况,可以传入适当的参数,甚至可以单独定义一个消息类
        void update();
    }
    

    抽象主题——Sentinel

    主题是使用抽象类还是接口根据情况而定。

    package io.github.brightloong.design.observer;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 哨兵,在有敌人入侵的时候通知其他士兵(弓兵、骑兵、步兵)准备迎战。
     * Created by BrightLoong on 2018/5/27.
     */
    public abstract class Sentinel {
        //持有的观察者集合
        private List<Soldier> soldiers = new ArrayList<Soldier>();
    
        /**
         * 添加观察者.
         * @param soldier
         */
        public void addSoldier(Soldier soldier) {
            soldiers.add(soldier);
        }
    
        /**
         * 移除观察者.
         * @param soldier
         */
        public void removeSoldier(Soldier soldier) {
            soldiers.remove(soldier);
        }
    
        /**
         * 通知所有观察者.
         */
        public void notifySoldier() {
            for (Soldier soldier : soldiers) {
                soldier.update();
            }
        }
    }
    

    具体主题——BraveSentinel

    package io.github.brightloong.design.observer;
    
    /**
     * Created by BrightLoong on 2018/5/27.
     */
    public class BraveSentinel extends Sentinel {
        /**哨兵的名字*/
        private String name;
    
        /**通知消息*/
        private String msg;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    }
    

    具体观察者

    弓兵

    package io.github.brightloong.design.observer;
    
    /**
     * Created by BrightLoong on 2018/5/27.
     */
    public class Archer implements Soldier {
    
        private BraveSentinel sentinel;
    
        /**
         * 构造函数,传入观察的主题,因为主题和观察者是一对多的情况,
         * 所以这里直接传入具体的BraveSentinel而不是Sentinel,
         * 当然,这个视具体情况而来
         * @param sentinel
         */
        public Archer(BraveSentinel sentinel) {
            this.sentinel = sentinel;
        }
    
    
        public void update() {
            System.out.println("收到哨兵" + sentinel.getName() + "的通知:" + sentinel.getMsg());
            System.out.println("弓兵布阵");
        }
    }
    
    

    骑兵

    package io.github.brightloong.design.observer;
    
    /**
     * 骑兵
     * Created by BrightLoong on 2018/5/27.
     */
    public class Cavalry implements Soldier {
        private BraveSentinel sentinel;
    
        public Cavalry(BraveSentinel sentinel) {
            this.sentinel = sentinel;
        }
    
        public void update() {
            System.out.println("收到哨兵" + sentinel.getName() + "的通知:" + sentinel.getMsg());
            System.out.println("骑兵上马布阵");
        }
    }
    

    客户端调用和输出

    package io.github.brightloong.design.observer;
    
    /**
     * Created by BrightLoong on 2018/5/27.
     */
    public class Client {
        public static void main(String[] args) {
            BraveSentinel sentinel = new BraveSentinel();
            sentinel.addSoldier(new Archer(sentinel));
            sentinel.addSoldier(new Cavalry(sentinel));
    
            sentinel.setName("小二郎");
            sentinel.setMsg("敌方十万大军来袭");
            sentinel.notifySoldier();
        }
    }
    

    输出如下:

    收到哨兵小二郎的通知:敌方十万大军来袭
    弓兵布阵
    收到哨兵小二郎的通知:敌方十万大军来袭
    骑兵上马布阵
    

    四. 总结

    使用场景

    • 当一个对象发生变化,同时其他对象需要因此而改变,并且它不知道具体有多少个对象会因此改变。
    • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
    • 需要建立一个触发链

    优点

    • 实现了观察者和被观察者的解耦,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
    • 可以方便的增加新的观察者和主题,方便扩展。

    缺点

    • 观察者的增加会导致通知所花费时间。

    相关文章

      网友评论

        本文标题:设计模式——观察者者模式

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