设计模式(观察者模式)

1.定义

当对象间存在一对多的依赖关系时,则使用观察者模式(Observer Pattern)。 比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。

2.概述

在许多设计中,经常涉及多个对象都对一个特殊对象中的数据变化感兴趣,而且这多个对象都希望跟踪那个特殊对象中的数据变化。 例如:某些寻找工作的人都对“求职中心”的职业需求信息的变化非常关心,想要跟踪“求职中心”中职业需求信息的变化。一位想知道“求职中心”职业需求信息变化的人,即让求职中心就会及时通知他最新的职业需求信息。如果一个求职者不想继续知道求职中心的职业需求信息,就让求职中心把自己从求职中心的求职者列表中删除,求职中心就不会在继续通知其他职业需求信息。
在这里插入图片描述

观察者模式是关于多个对象想知道一个对象中数据变化情况的一种成熟的模式。观察者模式中有一个称作“主题”的对象和若干个称作“观察者”的对象,“主题”和“观察者”间是一种一对多的依赖关系,当“主题”的状态发生变化时,所有的“观察者”都得到通知。前面所谈到的求职中心相当于观察者模式的一个具体“主题”;每个“求职者”相当于观察者模式中的一个具体“观察者”。

3.应用场景

1.一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
2.一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
3.一个对象必须通知其他对象,而并不知道这些对象是谁。
4.需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

4.模式的结构和使用

观察者模式的结构中一般包括四种角色,即:主题,观察者,具体主题,具体观察者。

1.观察者模式的UML类图

在这里插入图片描述

2.结构的描述

下面通过一个简单的问题来描述观察者模式中所涉及的各个角色,这个简单问题是:
有一个大学生毕业生和一个归国留学生都希望能够及时知道求职中心最新的职业需求信息。

1.主题

本问题中,主题接口Subject规定了具体主题需要实现的添加,删除观察者以及通知观察者更新数据的方法,具体如下所示:

package com.xing.observer;
public interface Subject {
    //添加观察者
    public void addObserver(Observer o);
    //删除观察者
    public void deleteObserver(Observer o);
    //通知所有观察者
    public void notifyObservers();
}
2.观察者

观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。hearTelephone方法是模拟观察者接听电话,即接受求职中心的信息。

public interface Observer {
    //模拟接听电话
    public void hearTelephone(String heardMess);
}
3.具体主题

在具体主题的实现类中,采用mess存储更新的求职信息,Boolean类型的changed表示信息是否更新,personList集合表示众多观察者的列表。除了实现了Subject接口里面的方法外,还新增了一个giveNewMess,即发布信息的方法。

package com.xing.observer;
import java.util.ArrayList;
//具体主题
public class SeekJobCenter implements Subject{
    String mess;
    boolean changed;
    ArrayList<Observer> personList;//存放观察者应用的数组线性表

    public SeekJobCenter() {
        personList=new ArrayList<>();
        mess="";
        changed=false;
    }
    @Override
    public void addObserver(Observer o) {
        if(!personList.contains(o)){
            personList.add(o);
        }
    }
    @Override
    public void deleteObserver(Observer o) {
        if(personList.contains(o)){
            personList.remove(o);
        }
    }

    @Override
    public void notifyObservers() {
        if(changed){
            //通知所有的观察者
            for (int i = 0; i < personList.size(); i++) {
                Observer observer=personList.get(i);
                //让观察者接电话
                observer.hearTelephone(mess);
            }
            changed=false;
        }
    }

    public void giveNewMess(String str){
        if (str.equals(mess))
            changed=false;
        else {
            mess=str;
            changed=true;
        }
    }
}
4.具体观察者

本问题中,实现观察者接口Observer的类有两个:一个是UniversityStudent类,另一个是HaiGui。UniversityStudent类的实例调用hearTelephone(String heardMess)方法时,会将参数引用的字符串保存到一个文件中。HaiGui类调用hearTelephone(String heardMess)方法时,如果参数引用的字符串包含“程序员”或“软件”,就将信息保存到一个文件中。具体实现分别如下所示:
UniversityStudent.java

package com.xing.observer;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class UniversityStudent implements Observer{
    Subject subject;
    File myFile;

    public UniversityStudent(Subject subject, String fileName) {
        this.subject=subject;
        //使当前实例称为subject所引用的具体主题的观察者
        subject.addObserver(this);
        myFile=new File(fileName);
    }

    //把求职中心传过来的信息写入文件
    @Override
    public void hearTelephone(String heardMess){
        try{
            RandomAccessFile out = new RandomAccessFile(myFile, "rw");
            out.seek(out.length());
            byte[] b = heardMess.getBytes();
            out.write(b);
            System.out.println("我是一个大学生");
            System.out.println("我向文件"+myFile.getName()+"写入如下内容");
            System.out.println(heardMess);
        }catch (IOException exp){
            System.out.println(exp.toString());
        }
    }
}

HaiGui.java

package com.xing.observer;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class HaiGui implements Observer{
    Subject subject;
    File myFile;

    public HaiGui(Subject subject, String fileName) {
        this.subject=subject;
        //使当前实例称为subject所引用的具体主题的观察者
        subject.addObserver(this);
        myFile=new File(fileName);
    }

    @Override
    public void hearTelephone(String heardMess){
        try{
            boolean boo=heardMess.contains("java程序员")||heardMess.contains("软件");
            if(boo){
                RandomAccessFile out = new RandomAccessFile(myFile, "rw");
                out.seek(out.length());
                byte[] b = heardMess.getBytes();
                out.write(b);
                System.out.println("我是一个海归");
                System.out.println("我向文件"+myFile.getName()+"写入如下内容");
                System.out.println(heardMess);
            }else{
                System.out.println("我是海归,这次的信息没有我需要的信息");
            }
        }catch (IOException exp){
            System.out.println(exp.toString());
        }
    }
}
5.主程序的编写

Application.java演示了一个大学生和留学生成为求职中心的观察者;当求职中心有新的人才需求信息时,大学生和归国留学生就将得到通知,具体实现如下所示:

package com.xing.observer;
//测试程序
public class Application {
    public static void main(String[] args) {
        SeekJobCenter center=new SeekJobCenter();//具体主题center
        UniversityStudent zhangLin=new UniversityStudent(center,"A.txt");
        HaiGui wangHai=new HaiGui(center,"B.txt");
        center.giveNewMess("腾讯公司需要10名java程序员");
        //通知所有的观察者
        center.notifyObservers();
        center.giveNewMess("阿里需要5名UI设计师");
        center.notifyObservers();
    }
}
6.执行结果展示

在这里插入图片描述

5.观察者模式的优点

1.具体主题和具体观察者是松耦合关系。
2.观察者模式满足“开闭原则”。 主题接口(Subject)仅仅依赖于观察者(Observer)接口, 这样,就可以让创建具体主题的类也仅仅是依赖于(Observer),因此,如果增加新的实现观察者接口(Observer)的类,则不必修改创建具体主题的类的代码。同样,创建具体观察者的类仅仅依赖于主题接口(Subject),如果增加新的实现主题接口(Subject)的类,也不必修改创建具体观察类的代码。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
1) 优秀的程序应该是这样的:阅读时,感觉很优雅;新增功能时,感觉很轻松;运行时,感觉很快速,这就需要设计模式支撑。2) 设计模式包含了大量的编程思想,讲授和真正掌握并不容易,网上的设计模式课程不少,大多讲解的比较晦涩,没有真实的应用场景和框架源码支撑,学习后,只知其形,不知其神。就会造成这样结果: 知道各种设计模式,但是不知道怎么使用到真实项目。本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,比如 单例模式的8种实现方式、工厂模式的3种实现方式、适配器模式的3种实现、代理模式的3种方式、深拷贝等3) 如果你想写出规范、漂亮的程序,就花时间来学习下设计模式吧课程内容和目标本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式1) 内容包括: 设计模式七大原则(单一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML类图(类的依赖、泛化和实现、类的关联、聚合和组合) 23种设计模式包括:创建型模式:单例模式(8种实现)、抽象工厂模式、原型模式、建造者模式、工厂模式。结构型模式:适配器模式(3种实现)、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式(3种实现)。行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)2) 学习目标:通过学习,学员能掌握主流设计模式,规范编程风格,提高优化程序结构和效率的能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

散一世繁华,颠半世琉璃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值