zoukankan      html  css  js  c++  java
  • 设计模式 #6 (观察者模式)

    设计模式 #6 (观察者模式)


    文章中所有工程代码和UML建模文件都在我的这个GitHub的公开库--->DesignPatternStar来一个好吗?秋梨膏!


    观察者模式

    简述:被观察者发生变化时,所有被观察者都会通知。

    需求:要求报纸发布的时候,读者可以及时收到报纸的最新报道。

    根据之前多次的反例经验,要做好面向接口和抽象编程的设计。

    这次直接上,

    正例 #1:

    为观察者定义一个接口。

    //观察者接口
     interface  Observer {
         void update(String Data);
    
         void disObservered(TheSubject subject);
    
         void doObservered(TheSubject subject);
    }
    

    这里有一个问题:为什么不用抽象类进行抽象?

    因为不知道观察者模式的应用都是怎么样的。现实编程中,具体的观察者完全有可能是风马牛不相及的类,但它们都需要根据通知者的通知来做出update()的操作,所以让它们都实现Observer接口,并重写相关方法即可。

    定义一个观察者:

    public class Reader implements Observer{
        private String name ;
    
        public Reader(String name) {
            this.name = name;
        }
    
        @Override
        public void update(String Data) {
            System.out.println(this.name+"收到报纸,阅读最新报道:"+Data);
        }
    
        @Override
        public void disObservered(TheSubject subject) {
            subject.removeObserver(this);
        }
    
        @Override
        public void doObservered(TheSubject subject) {
            subject.addObserver(this);
        }
    }
    
    //被观察者抽象类
    public abstract class TheSubject {
        //观察者列表
        protected List<Observer> observerList = new ArrayList<>();
        //加入到观察者列表
        public  boolean addObserver(Observer observer){
            return  observerList.add(observer);
        }
        //从观察者列表移除
        public  boolean removeObserver(Observer observer){
            return observerList.remove(observer);
        }
        //变化,并通知观察者
        public abstract void setChange(String Data);
        //为观察者更新内容
        public abstract void upDataObserver(String Data);
    }
    

    唉?那这里为什么不可以用接口呢?

    注意到有一个变量observerList了吗?

    我们先假设TheSubject抽象类是一个接口,如果是需要一个类成为被观察者,那么就会让他实现这一接口,也是需要定义它的观察者列表observerList,如果是每一个被观察者都需要重新定义自己的观察者列表observerList,还要在实现addObserverremoveObserver两个方法,这两个方法都是固定的算法。重复太多的代码就会有坏的味道的。

    这时候,将重复的代码写在抽象类TheSubject,被观察者进行继承即可。

    public class News_pappers extends TheSubject{
        private  String news;
    
        public String getNews() {
            return news;
        }
    
        @Override
        public void setChange(String Data) {
            this.news ="最新报道:"+ Data;
            System.out.println("发布最新报道:"+Data);
            upDataObserver(Date);
        }
    
        @Override
        public void upDataObserver(String Data) {
            for (Observer observer : observerList) {
                observer.update(Data);
            }
        }
    }
    
    public class postive {
    /*================客户端============================*/
        public static void main(String[] args) {
            News_pappers newspaper = new News_pappers();
            Reader lili = new Reader("lili");
            Reader mumu = new Reader("mumu");
            Reader shanshan = new Reader("shanshan");
    
            newspaper.addObserver(lili);
            newspaper.addObserver(mumu);
            newspaper.addObserver(shanshan);
    
            newspaper.setChange("Big News");
    
            shanshan.disObservered(newspaper);
    
            newspaper.setChange("small00000 News");
    
            News_pappers news_pappers_02 = new News_pappers();
            mumu.doObservered(news_pappers_02);
            news_pappers_02.setChange("大新闻");
    
        }
    }
    

    运行结果:

    image-20200921201557214

    UML类图:

    image-20200921204803554

    细心的读者可能已经发现,这里遵守的设计原则有:

    • 增加其他类型观察者时,只需要Observer接口即可;增加被观察者继承抽象类TheSubject即可,符合开闭原则
    • 接口Observer和抽象类TheSubject相互依赖,并不涉及相关具体的观察者和被观察者,符合依赖倒置原则

    其实接触过安卓都知道,安卓的内容提供者和内容观察者,广播机制都有点观察者模式的味道。

    最后总结观察者模式:

    • 当一个对象的改变需要同时改变其他对象的时候,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。
    • 当一个抽象模型有两个方面,其中一方面依赖于另一方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用
    • 观察者模式所做的工作其实就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。
    • 观察者和被观察者可以是多对多的关系。
    • 观察者抽象成接口,被观察者抽象于抽象类比较合适。

    这是最后一篇关于设计模式的相关随笔,回顾以往设计模式相关原创随笔请点击---> 设计原则和常用设计模式

  • 相关阅读:
    JVM运行参数
    JVM学习
    自己瞎写的小项目随笔
    git入门
    @ResponseBody 注释
    jquery 正则表达式 验证邮箱 手机号 座机号 身份证
    ORACLE计算一年的12个月份
    css 图片 文字居中
    Jquery 取值相关
    标题栏下拉菜单
  • 原文地址:https://www.cnblogs.com/l1ng14/p/13708718.html
Copyright © 2011-2022 走看看