求职华为,被问观察者模式,从没有这种体验!!!

求职华为,被问观察者模式,从没有这种体验!!!

  • 模式的定义与特点
  • 模式的结构与实现
    • 1. 模式的结构
    • 2. 模式的实现
  • 模式的应用实例
  • 模式的应用场景
    • 模式的扩展
    • 1. Observable类
    • 2. Observer 接口

[

观察者模式可以说是非常贴近我们生活的一个设计模式,为什么这么说呢?哲学上有这么一种说法,叫做“万事万物皆有联系”,原意是说世上没有孤立存在的事物,但其实也可以理解为任何一个事件的发生必然由某个前置事件引起,也必然会导致另一个后置事件。

我们的生活中,充斥着各种各样的相互联系的事件,而观察者模式,主要就是用于处理这种事件的一套解决方案。

模式的定义与特点

观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

观察者模式是一种对象行为型模式,其主要优点如下。

降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
目标与观察者之间建立了一套触发机制。
它的主要缺点如下。

目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

模式的结构与实现

实现观察者模式时要注意具体目标对象和具体观察者对象之间不能直接调用,否则将使两者之间紧密耦合起来,这违反了面向对象的设计原则。

1. 模式的结构

观察者模式的主要角色如下。

  • 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。

  • 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。

  • 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。

  • 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
    观察者模式的结构图如图 1 所示。

2. 模式的实现

观察者模式的实现代码如下:

package net.biancheng.c.observer;
import java.util.*;
public class ObserverPattern {public static void main(String[] args) {Subject subject = new ConcreteSubject();Observer obs1 = new ConcreteObserver1();Observer obs2 = new ConcreteObserver2();subject.add(obs1);subject.add(obs2);subject.notifyObserver();}
}
//抽象目标
abstract class Subject {protected List<Observer> observers = new ArrayList<Observer>();//增加观察者方法public void add(Observer observer) {observers.add(observer);}//删除观察者方法public void remove(Observer observer) {observers.remove(observer);}public abstract void notifyObserver(); //通知观察者方法
}//加入Java开发交流君样:756584822一起吹水聊天
//具体目标
class ConcreteSubject extends Subject {public void notifyObserver() {System.out.println("具体目标发生改变...");System.out.println("--------------");for (Object obs : observers) {((Observer) obs).response();}}
}
//抽象观察者
interface Observer {void response(); //反应
}
//具体观察者1
class ConcreteObserver1 implements Observer {public void response() {System.out.println("具体观察者1作出反应!");}
}//加入Java开发交流君样:756584822一起吹水聊天
//具体观察者1
class ConcreteObserver2 implements Observer {public void response() {System.out.println("具体观察者2作出反应!");}
}

模式的应用实例

【例1】利用观察者模式设计一个程序,分析“人民币汇率”的升值或贬值对进口公司进口产品成本或出口公司的出口产品收入以及公司利润率的影响。
分析:当“人民币汇率”升值时,进口公司的进口产品成本降低且利润率提升,出口公司的出口产品收入降低且利润率降低;当“人民币汇率”贬值时,进口公司的进口产品成本提升且利润率降低,出口公司的出口产品收入提升且利润率提升。

这里的汇率(Rate)类是抽象目标类,它包含了保存观察者(Company)的 List 和增加/删除观察者的方法,以及有关汇率改变的抽象方法 change(int number);而人民币汇率(RMBrate)类是具体目标, 它实现了父类的 change(int number) 方法,即当人民币汇率发生改变时通过相关公司;公司(Company)类是抽象观察者,它定义了一个有关汇率反应的抽象方法 response(int number);进口公司(ImportCompany)类和出口公司(ExportCompany)类是具体观察者类,它们实现了父类的 response(int number) 方法,即当它们接收到汇率发生改变的通知时作为相应的反应。图 2 所示是其结构图。
[

程序代码如下:

package net.biancheng.c.observer;
import java.util.*;
public class RMBrateTest {public static void main(String[] args) {Rate rate = new RMBrate();Company watcher1 = new ImportCompany();Company watcher2 = new ExportCompany();rate.add(watcher1);rate.add(watcher2);rate.change(10);rate.change(-9);}//加入Java开发交流君样:756584822一起吹水聊天
}
//抽象目标:汇率
abstract class Rate {protected List<Company> companys = new ArrayList<Company>();//增加观察者方法public void add(Company company) {companys.add(company);}//删除观察者方法public void remove(Company company) {companys.remove(company);}public abstract void change(int number);
}
//具体目标:人民币汇率
class RMBrate extends Rate {public void change(int number) {for (Company obs : companys) {((Company) obs).response(number);}}//加入Java开发交流君样:756584822一起吹水聊天
}
//抽象观察者:公司
interface Company {void response(int number);
}
//具体观察者1:进口公司
class ImportCompany implements Company {public void response(int number) {if (number > 0) {System.out.println("人民币汇率升值" + number + "个基点,降低了进口产品成本,提升了进口公司利润率。");} else if (number < 0) {System.out.println("人民币汇率贬值" + (-number) + "个基点,提升了进口产品成本,降低了进口公司利润率。");}}
}
//具体观察者2:出口公司
class ExportCompany implements Company {public void response(int number) {if (number > 0) {System.out.println("人民币汇率升值" + number + "个基点,降低了出口产品收入,降低了出口公司的销售利润率。");} else if (number < 0) {System.out.println("人民币汇率贬值" + (-number) + "个基点,提升了出口产品收入,提升了出口公司的销售利润率。");}}
}


现在用“观察者模式”来实现该事件处理模型。
首先,定义一个铃声事件(RingEvent)类,它记录了铃声的类型(上课铃声/下课铃声)。
再定义一个学校的铃(BellEventSource)类,它是事件源,是观察者目标类,该类里面包含了监听器容器 listener,可以绑定监听者(学生或老师),并且有产生铃声事件和通知所有监听者的方法。
然后,定义铃声事件监听者(BellEventListener)类,它是抽象观察者,它包含了铃声事件处理方法 heardBell(RingEvent e)。
最后,定义老师类(TeachEventListener)和学生类(StuEventListener),它们是事件监听器,是具体观察者,听到铃声会去上课或下课。图 4 给出了学校铃声事件处理程序的结构。


程序代码如下:

package net.biancheng.c.observer;
import java.util.*;
public class BellEventTest {public static void main(String[] args) {BellEventSource bell = new BellEventSource();    //铃(事件源)bell.addPersonListener(new TeachEventListener()); //注册监听器(老师)bell.addPersonListener(new StuEventListener());    //注册监听器(学生)bell.ring(true);   //打上课铃声System.out.println("------------");bell.ring(false);  //打下课铃声}//加入Java开发交流君样:756584822一起吹水聊天
}
//铃声事件类:用于封装事件源及一些与事件相关的参数
class RingEvent extends EventObject {private static final long serialVersionUID = 1L;private boolean sound;    //true表示上课铃声,false表示下课铃声public RingEvent(Object source, boolean sound) {super(source);this.sound = sound;}public void setSound(boolean sound) {this.sound = sound;}public boolean getSound() {return this.sound;}
}
//目标类:事件源,铃
class BellEventSource {private List<BellEventListener> listener; //监听器容器public BellEventSource() {listener = new ArrayList<BellEventListener>();}//给事件源绑定监听器public void addPersonListener(BellEventListener ren) {listener.add(ren);}//事件触发器:敲钟,当铃声sound的值发生变化时,触发事件。public void ring(boolean sound) {String type = sound ? "上课铃" : "下课铃";System.out.println(type + "响!");RingEvent event = new RingEvent(this, sound);notifies(event);    //通知注册在该事件源上的所有监听器}//加入Java开发交流君样:756584822一起吹水聊天//当事件发生时,通知绑定在该事件源上的所有监听器做出反应(调用事件处理方法)protected void notifies(RingEvent e) {BellEventListener ren = null;Iterator<BellEventListener> iterator = listener.iterator();while (iterator.hasNext()) {ren = iterator.next();ren.heardBell(e);}}
}
//抽象观察者类:铃声事件监听器
interface BellEventListener extends EventListener {//事件处理方法,听到铃声public void heardBell(RingEvent e);
}
//具体观察者类:老师事件监听器
class TeachEventListener implements BellEventListener {public void heardBell(RingEvent e) {if (e.getSound()) {System.out.println("老师上课了...");} else {System.out.println("老师下课了...");}}
}//加入Java开发交流君样:756584822一起吹水聊天
//具体观察者类:学生事件监听器
class StuEventListener implements BellEventListener {public void heardBell(RingEvent e) {if (e.getSound()) {System.out.println("同学们,上课了...");} else {System.out.println("同学们,下课了...");}}
}

模式的应用场景

在软件系统中,当系统一方行为依赖另一方行为的变动时,可使用观察者模式松耦合联动双方,使得一方的变动可以通知到感兴趣的另一方对象,从而让另一方对象对此做出响应。
通过前面的分析与应用实例可知观察者模式适合以下几种情形。

  • 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象。
  • 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时,可将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
  • 实现类似广播机制的功能,不需要知道具体收听者,只需分发广播,系统中感兴趣的对象会自动接收该广播。
  • 多层级嵌套使用,形成一种链式触发机制,使得事件具备跨域(跨越两种观察者类型)通知。

模式的扩展

在 Java 中,通过 java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例。

1. Observable类

Observable 类是抽象目标类,它有一个 Vector 向量,用于保存所有要通知的观察者对象,下面来介绍它最重要的 3 个方法。

  • void addObserver(Observer o) 方法:用于将新的观察者对象添加到向量中。
  • void notifyObservers(Object arg) 方法:调用向量中的所有观察者对象的 update() 方法,通知它们数据发生改变。通常越晚加入向量的观察者越先得到通知。
  • void setChange() 方法:用来设置一个 boolean 类型的内部标志位,注明目标对象发生了变化。当它为真时,notifyObservers() 才会通知观察者。

2. Observer 接口

Observer 接口是抽象观察者,它监视目标对象的变化,当目标对象发生变化时,观察者得到通知,并调用 void update(Observable o,Object arg) 方法,进行相应的工作。

【例3】利用 Observable 类和 Observer 接口实现原油期货的观察者模式实例。

分析:当原油价格上涨时,空方伤心,多方局兴;当油价下跌时,空方局兴,多方伤心。本实例中的抽象目标(Observable)类在 Java 中已经定义,可以直接定义其子类,即原油期货(OilFutures)类,它是具体目标类,该类中定义一个SetPriCe(float price) 方法,当原油数据发生变化时调用其父类的 notifyObservers(Object arg) 方法来通知所有观察者;另外,本实例中的抽象观察者接口(Observer)在 Java 中已经定义,只要定义其子类,即具体观察者类(包括多方类 Bull 和空方类 Bear),并实现update(Observable o,Object arg)方法即可。图 5 所示是其结构图。
[

package net.biancheng.c.observer;
import java.util.Observer;
import java.util.Observable;
public class CrudeOilFutures {public static void main(String[] args) {OilFutures oil = new OilFutures();Observer bull = new Bull(); //多方Observer bear = new Bear(); //空方oil.addObserver(bull);oil.addObserver(bear);oil.setPrice(10);oil.setPrice(-8);}//加入Java开发交流君样:756584822一起吹水聊天
}
//具体目标类:原油期货
class OilFutures extends Observable {private float price;public float getPrice() {return this.price;}public void setPrice(float price) {super.setChanged();  //设置内部标志位,注明数据发生变化super.notifyObservers(price);    //通知观察者价格改变了this.price = price;}
}
//具体观察者类:多方
class Bull implements Observer {public void update(Observable o, Object arg) {Float price = ((Float) arg).floatValue();if (price > 0) {System.out.println("油价上涨" + price + "元,多方高兴了!");} else {System.out.println("油价下跌" + (-price) + "元,多方伤心了!");}}
}
//具体观察者类:空方
class Bear implements Observer {public void update(Observable o, Object arg) {Float price = ((Float) arg).floatValue();if (price > 0) {System.out.println("油价上涨" + price + "元,空方伤心了!");} else {System.out.println("油价下跌" + (-price) + "元,空方高兴了!");}}
}

最后,祝大家早日学有所成,拿到满意offer

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/299651.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL2005的配置

最近迷上c#&#xff0c;下午装好了SQL server management studio Express 附加经典的northwind数据库 然后用下面一段代码测试 1usingSystem;2usingSystem.Collections.Generic;3usingSystem.Text;4usingSystem.Data;5usingSystem.Data.Sql;6usingSystem.Data.SqlClient;78name…

为什么应该用record来定义DTO(续)

前言上次&#xff0c;我们介绍了因为DTO的“不变性”&#xff0c;应该用record来定义DTO。今天&#xff0c;我们来说明用record来定义DTO的另一个好处。问题首先&#xff0c;我们实现一个Controler&#xff0c;代码如下:[ApiController] [Route("[controller]")] pub…

字节、编码、字符、字符集 专题

1.2 字符&#xff0c;字节&#xff0c;字符串 理解编码的关键&#xff0c;是要把字符的概念和字节的概念理解准确。这两个概念容易混淆&#xff0c;我们在此做一下区分&#xff1a; 概念描述举例字符人们使用的记号&#xff0c;抽象意义上的一个符号。1, 中, a, $, &#xffe5…

资料分享 | 数学建模竞赛备战大全

全世界只有3.14 % 的人关注了青少年数学之旅目前针对数学建模的认知&#xff0c;绝大部分人还停留在数学建模竞赛阶段&#xff0c;并不知道数学建模是数据领域非常重要的一种方法。数学建模涉及的内容广泛&#xff0c;比如碎纸片问题中所涉及的图像识别及神经网络、小区开放问题…

TC的文件拷贝/移动

在EX当中&#xff0c;我们比较常用的拷贝/移动文件/目录的方式就是先进行文件/目录定位&#xff0c;然后按CtrlC,Ctrlx&#xff0c;然后在移动到目标目录&#xff0c;再按Ctrlv&#xff0c;通过拷贝/剪切和粘贴的方式进行。文件在拷贝/过程当中只有一个对话框显示当前进度&…

初级Java开发工程师!绝密文档,面试手册全面突击!!!秋招已经到来

这里我要明说一下&#xff0c;不是Java初级和学习Java的千万不要乱看&#xff0c;否则~~~~ 你会怀疑人生&#xff0c;因为会浪费你时间啊&#xff01;&#xff01;&#xff01; 本次考点是Java初级开发工程师面试必备的一些东西!!! 1、数据类型 基本类型 byte/8、short/16、…

数学2600年,欧拉凭什么能当上“大王”?

全世界只有3.14 % 的人关注了青少年数学之旅何为数学&#xff1f;♠音乐家说&#xff0c;数学是世界上最和谐动听的音符♥植物学家说&#xff0c;世界上没有比数学更美的花朵♣美学家说&#xff0c;哪里有数学&#xff0c;哪里才有真正的美♦哲学家说&#xff0c;世界什么都在变…

NET流行高性能JSON框架-Json.NET

在日常编程中经常会使用到Json来进行数据的交互好在.Net平台下有很多开源的Json库使得我们能够比较轻松快速的处理各种复杂的Json&#xff0c;其中Newtonsoft库是NET的流行高性能JSON框架特性工具VS2010Newtonsoft库从NuGet下载合适的Newtonsoft.Json库1.在你需要引用Newtosoft…

Tcpdump 详解

TcpDump可以将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤&#xff0c;并提供and、or、not等逻辑语句来帮助你去掉无用的信息。和Linux终端状态下的其他软件一样&#xff0c;TcpDump也是依靠参数来工作&#xff0c;本文将…

敢叫岁月不冬天

敢叫岁月不冬天题记&#xff1a;观看人民公园千菊会有感——代腾飞 2009年11月21日 于成都绿柳成荫似境仙秋菊满园锦上添红黄白紫竞展颜要留秋月不冬天转载于:https://www.cnblogs.com/daitengfei/archive/2009/11/22/1607976.html

Scribefire发CSDN博客

历史在非常久非常久曾经&#xff0c;CSDN是支持外部工具来写文章的&#xff0c;但是在还有一个非常久非常久曾经就不行了。突然看到CSDN有能够用外部工具来写博客了&#xff08;CSDN的公告&#xff09;&#xff0c;一直以来都纠结这个问题&#xff0c;CSDN的编辑器不好用&#…

今日笔记!——分析Java应用性能

1 问题描述 因产品架构的复杂性&#xff0c;可能会导致性能问题的因素有很多。根据部署架构&#xff0c;大致的可以分为应用端瓶颈、数据库端瓶颈、环境瓶颈三大类。可以根据瓶颈的不同部位&#xff0c;选择相应的跟踪工具进行跟踪分析。 应用层面瓶颈大致有如下两类&#xf…

除了PS,还有它可以轻松实现图像处理!

全世界只有3.14 % 的人关注了青少年数学之旅在我们生活中&#xff0c;常见的图像处理软件有Adobe Photoshop、Adobe Illustrator等。然而&#xff0c;并非只有软件才能实现图像处理&#xff0c;通过编程手段也是能实现的&#xff01;今天&#xff0c;小天将要带着大家走进计算机…

微服务并不能解决你的烂代码问题

点击上方蓝字关注我们“微服务并不能解决你的烂代码问题很久以来&#xff0c;软件的交付质量一直是一个大家比较关心的问题&#xff0c;而程序员和架构师也一直在极力寻找一种更好的方式来构建应用系统。随着互联网爆炸式的增长&#xff0c;对于系统的交付速度和质量的要求也日…

不要设计模式

看到首页讲设计模式的文章和书&#xff0c;有些感慨抒发一下。我买过一本设计模式的书&#xff0c;基本上看了&#xff12;&#xff14;个模式的名称&#xff0c;大致把这几个名字记住了&#xff0c;我并没有沉下心来深入理解&#xff0c;并不是书讲得不好&#xff0c;我是一个…

protobuf在java应用中通过反射动态创建对象

2019独角兽企业重金招聘Python工程师标准>>> ---恢复内容开始--- 最近编写一个游戏用到protobuf数据格式进行前后台传输&#xff0c;苦于protobuf接受客户端的数据时是需要数据类型的如xxx.parseForm(...),这样就要求服务器在接受客户端请求时必须知道客户端传递的数…

[轉]数据挖掘工具的选择

轉自:http://blog.csdn.net/redvalley/archive/2006/02/06/593233.aspx 一、数据挖掘工具分类   数据挖掘工具根据其适用的范围分为两类&#xff1a;专用挖掘工具和通用挖掘工具。 专用数据挖掘工具是针对某个特定领域的问题提供解决方案&#xff0c;在涉及算法的时候充分考虑…

Java秘技之Json数据解析与转换 -- Java使用示例

概要 json是前后台交互常用的数据格式&#xff0c;在java后台中经常需要实现java bean、list和json字符串的相互转化&#xff0c;故简单介绍不同框架的使用&#xff0c;提供简单工具类。 在Java中&#xff0c;常见的json框架有&#xff1a;Jackson&#xff08;springboot默认…

黑科技轮胎:有能发电的,脑洞简直不要太大...

全世界只有3.14 % 的人关注了青少年数学之旅人类历史上的很多伟大发明&#xff0c;都是由脑洞产生的&#xff0c;这样那样&#xff0c;然后问题就解决了&#xff0c;过程很复杂&#xff0c;却又很简单&#xff0c;甚至有时候&#xff0c;是一种很奇葩的方式。在漫长的历史进程中…

将权限授予文件夹和程序集

http://technet.microsoft.com/zh-cn/office/zdc263t0.aspx 如何&#xff1a;将权限授予文件夹和程序集 (2003 System) 注意 适用于 本主题中的信息仅适用于指定的 Visual Studio Tools for Office 项目和 Microsoft Office 版本。 有关更多信息&#xff0c;请参见按应用程序…