• 18 行为型模式-观察者模式


    行为模式共有11种:
    在这里插入图片描述
    观察者模式
    模板方法模式
    策略模式
    职责链模式
    状态模式
    命令模式
    中介者模式
    迭代器模式
    访问者模式
    备忘录模式
    解释器模式

    以上 11 种行为型模式,除了模板方法模式解释器模式是类行为型模式,其他的全部属于对象行为型模式。

    1 观察者模式介绍

    在这里插入图片描述
    在这里插入图片描述

    2 观察者模式原理

    在这里插入图片描述
    在这里插入图片描述

    3 观察者模式实现
    /**
     * 抽象观察者
     **/
    public interface Observer {
        //update方法: 为不同的观察者更新行为定义一个相同的接口,不同的观察者对该接口有不同的实现
        public void update();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    /**
     * 具体的观察者
     **/
    public class ConcreteObserver1 implements Observer {
    
        @Override
        public void update() {
            System.out.println("ConcreteObserver1 得到通知,更新状态! !");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    public class ConcreteObserver2  implements Observer{
        @Override
        public void update() {
            System.out.println("ConcreteObserver2 得到通知,更新状态! !");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    /**
     * 抽象目标类
     **/
    public interface Subject {
        void attach(Observer observer);
        void detach(Observer observer);
        void notifyObservers();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    import java.util.ArrayList;
    
    /**
     * 具体目标类
     **/
    public class ConcreteSubject implements Subject {
    
        //定义集合,存储所有的观察者对象
        private ArrayList<Observer> observers = new ArrayList<>();
    
    
        //注册方法,向观察者集合增加一个观察者
        @Override
        public void attach(Observer observer) {
            observers.add(observer);
        }
    
        //注销方法,用于从观察者集合中移除一个观察者
        @Override
        public void detach(Observer observer) {
            observers.remove(observer);
        }
    
        //通知方法
        @Override
        public void notifyObservers() {
            //遍历集合,调用每一个观察者的响应方法
            for (Observer observer : observers) {
                observer.update();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    public class Client {
    
        public static void main(String[] args) {
    
            //创建目标类
            Subject subject = new ConcreteSubject();
    
            //注册观察者,注册多个
            subject.attach(new ConcreteObserver1());
            subject.attach(new ConcreteObserver2());
    
            //具体的主题内部发生改变,给所有注册的观察者发送通知
            subject.notifyObservers();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    4 观察者模式应用实例

    来实现一个买房摇号的程序.摇号结束,需要通过短信告知用户摇号结果,还需要向MQ中保存用户本次摇号的信息.

    1 ) 未使用设计模式
    /**
     * 模拟买房摇号服务
     **/
    public class DrawHouseService {
    
        //摇号抽签
        public String lots(String uId){
            if(uId.hashCode() % 2 == 0){
                return "恭喜ID为: " + uId + " 的用户,在本次摇号中中签!" ;
            }else{
                return "很遗憾,ID为: " + uId + "的用户,您本次未中签!" ;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    /**
     * 开奖结果封装类
     **/
    public class LotteryResult {
    
        private String uId; //用户id
    
        private String msg; //摇号信息
    
        private Date dateTime; //业务时间
    
        public LotteryResult(String uId, String msg, Date dateTime) {
            this.uId = uId;
            this.msg = msg;
            this.dateTime = dateTime;
        }
    
        @Override
        public String toString() {
            return "LotteryResult{" +
                    "uId='" + uId + '\'' +
                    ", msg='" + msg + '\'' +
                    ", dateTime=" + dateTime +
                    '}';
        }
    
        public String getuId() {
            return uId;
        }
    
        public void setuId(String uId) {
            this.uId = uId;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public Date getDateTime() {
            return dateTime;
        }
    
        public void setDateTime(Date dateTime) {
            this.dateTime = dateTime;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    /**
     * 开奖服务接口
     **/
    public interface LotteryService {
        //开奖之后的业务操作
        public LotteryResult lottery(String uId);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    public class LotteryServiceImpl implements LotteryService {
    
        //注入摇号服务
        private DrawHouseService houseService = new DrawHouseService();
    
        @Override
        public LotteryResult lottery(String uId) {
            //1.摇号
            String result = houseService.lots(uId);
    
            //2.发短信
            System.out.println("发送短信通知用户,ID为: " + uId +",您的摇号结果如下: " + result);
    
            //3.发送MQ信息
            System.out.println("记录用户摇号结果到MQ,ID为: " + uId +",摇号结果: " + result);
    
            return new LotteryResult(uId,result,new Date());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    使用观察者模式进行优化

    在这里插入图片描述

    /**
     * 事件监听接口
     **/
    public interface EventListener {
    	//充当观察者的角色,对结果进行监听
        void doEvent(LotteryResult result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    /**
     * 短信发送事件监听类
     **/
    public class MessageEventListener implements EventListener {
        @Override
        public void doEvent(LotteryResult result) {
            System.out.println("发送短信通知,用户ID: " + result.getuId()
            +",您的摇号结果为: " + result.getMsg());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    /**
     * MQ消息发送事件监听
     **/
    public class MQEventListener implements EventListener{
    
        @Override
        public void doEvent(LotteryResult result) {
            System.out.println("记录用户的摇号结果(MQ),用户ID: " + result.getuId()
            + ",摇号结果: " + result.getMsg());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    /**
     * 事件处理类
     **/
    public class EventManager {
    
        public enum EventType{
            MQ,Message
        }
    
        //监听器集合
        Map<Enum<EventType>, List<EventListener>> listeners = new HashMap<>();
    
        public EventManager(Enum<EventType>... operations) {
            for (Enum<EventType> operation : operations) {
                this.listeners.put(operation,new ArrayList<>());
            }
        }
    
        /**
         * 订阅
         * @param eventType 事件类型
         * @param listener  监听对象
         */
        public void subscribe(Enum<EventType> eventType,EventListener listener){
            List<EventListener> users = listeners.get(eventType);
            users.add(listener);
        }
    
        /**
         * 取消订阅
         * @param eventType 事件类型
         * @param listener  监听对象
         */
        public void unsubscribe(Enum<EventType> eventType,EventListener listener){
            List<EventListener> users = listeners.get(eventType);
            users.remove(listener);
        }
    
        /**
         * 通知
         * @param eventType
         * @param result
         */
        public void notify(Enum<EventType> eventType, LotteryResult result){
            List<EventListener> users = listeners.get(eventType);
            for (EventListener listener : users) {
                listener.doEvent(result);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    /**
     * 开奖服务接口
     **/
    public abstract class LotteryService {
    
        private EventManager eventManager;
    
        public LotteryService() {
            //设置事件的类型
            eventManager = new EventManager(EventManager.EventType.MQ,EventManager.EventType.Message);
            //订阅
            eventManager.subscribe(EventManager.EventType.Message,new MessageEventListener());
            eventManager.subscribe(EventManager.EventType.MQ,new MQEventListener());
        }
    
        public LotteryResult lotteryAndMsg(String uId){
            LotteryResult lottery = lottery(uId);
            //发送通知
            eventManager.notify(EventManager.EventType.Message,lottery);
            eventManager.notify(EventManager.EventType.MQ,lottery);
    
            return lottery;
        }
    
        public abstract LotteryResult lottery(String uId);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    public class LotteryServiceImpl extends LotteryService {
    
        //注入摇号服务
        private DrawHouseService houseService = new DrawHouseService();
    
        @Override
        public LotteryResult lottery(String uId) {
            //1.摇号
            String result = houseService.lots(uId);
            return new LotteryResult(uId,result,new Date());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    测试

    @Test
    public void test2(){
    	LotteryService ls = new LotteryServiceImpl();
    	LotteryResult result = ls.lotteryAndMsg("1234567887654322");
    	System.out.println(result);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    5 观察者模式总结

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    基于SqlSugar的开发框架循序渐进介绍(29)-- 快速构建系统参数管理界面-Vue3+ElementPlus
    GO语言学习笔记(与Java的比较学习)(三)
    花2个月时间学习,面华为测开岗要30k,面试官竟说:你不是在....
    MYSQL索引使用注意事项
    【python】Conda强大的包/环境管理工具
    用函数的递归来解决几道有趣的题
    IDLE、Anaconda安装与使用
    自动推理的逻辑04-命题微积分
    Word 文档转换 PDF、图片
    随机森林实战(分类任务+特征重要性+回归任务)(含Python代码详解)
  • 原文地址:https://blog.csdn.net/weixin_39563769/article/details/134038377