Head first设计模式(2)

认识观察者模式java

咱们看看报纸和杂志的订阅是怎么回事:编程

1、报社的业务就是出版报纸测试

2、向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,你就会一直收到新报纸spa

3、当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来设计

4、只要报社还在运营,就会一直有人(或单位)向他们订阅报纸或取消订阅报纸orm

 

出版者+订阅者=观察者模式server

若是你了解报纸的订阅是怎么回事,其实就知道观察者模式是怎么回事,只是名称不太同样:出版者改称为“主题”(Subject),订阅者改称为"观察者"(Observer)对象

1、主题对象管理某些数据继承

2、当主题内的数据改变就会通知观察者接口

3、一旦数据改变,新的数据会以某种形式送到观察者手上

4、观察者订阅(注册)主题以便在主题数据改变时可以收到更新

5、某个对象不是观察者,因此在主题数据改变使不会被通知

 

观察者的一天

1、鸭子对象过来告诉主题,它至关一个观察者

2、鸭子其实想说的是:我对你的数据改变感兴趣,一有变化请通知我

3、鸭子对象如今已是正式的观察者了

4、鸭子静候通知,等待参与这项伟大的事情。一旦接获通知,就会获得一个整数

5、主题有了新的数据值

6、如今鸭子和其余全部观察者都会收到通知:主题已经改变了

7、老鼠对象要求从观察者中把本身除名

8、老鼠已经观察此主题过久,厌倦了,因此决定再也不当个观察者

9、老鼠离开了

10、主题知道老鼠的请求以后,把它从观察者中除名

11、主题有一个新的整数

12、除了老鼠以外,每一个观察者都会收到通知,由于它已经被除名了。嘘!不要告诉别人,老鼠其实心中暗暗地怀念这个整数,或许哪天又会再次注册,回来继续当观察者

 

定义观察者模式

1、当你试图勾勒观察者模式时,能够利用报纸订阅服务,以及出版者和订阅者比拟这一切

2、在真实的世界中,你一般会看到观察者模式被定义成

3、观察者模式——定义了对象之间的一对多依赖,这样依赖,当一个对象改变状态时,它的全部依赖者都会收到通知并自动更新

4、主题和观察者定义了一对多的关系,观察者依赖于此主题,只要主题状态一有变化,观察者就会被通知。根据通知的风格,观察者可能所以新值而更新

5、实现观察者模式的方法不仅一种,可是以包含SubjectObserver接口的类设计的作法最多见

 

定义观察者模式:类图

1、这是主题接口,对象使用此接口注册为观察者,或者把本身从观察者中删除

2、每一个主题能够有许多观察者

3、全部潜在的观察者必须实现观察者接口,这个接口只有update()一个方法,当主题状态改变时它被调用

4、一个具体主题老是实现主题接口,除了注册和撤销方法以外,具体主题还实现了notifyObservers()方法,此方法用于在状态改变时更新全部当前观察者

5、具体主题也可能有设置和获取状态的方法

6、具体的观察者能够是实现此接口的任意类。观察者必须注册具体主题,以便接收更新

 

这和一对多的关系有何关联?

利用观察者模式,主题是具备状态的对象,而且能够控制这些状态。也就是说,有“一个”具备状态的主题。另外一方面,观察者使用这些状态,虽然这些状态并不属于它们。、有许多的观察者,依赖主题告诉它们状态什么时候改变了。这就产生一个关系:"一个"主题对“多个”观察者的关系

 

其间的依赖是如何产生的?

由于主题是真正拥有数据的人,观察者是主题的依赖者,在数据变化时更新,这样比起让许多对象控制同一份数据来,能够获得更干净的OO设计

 

松耦合的威力

1、当两个对象之间松耦合,它们依赖能够交互,可是不太清楚彼此的细节

2、观察者模式提供了一种对象设计,让主题和观察者之间松耦合

为何?

1、关于观察者的一切,主题只知道观察者实现了某一个接口(也就是Observer接口)。主题不须要知道观察者的具体类是谁,作了些什么或其余任何细节

2、任什么时候候咱们均可以增长新的观察者。由于主题惟一依赖的东西是一个实现Observer接口的对象列表,因此咱们能够随时增长观察者。事实上,在运行时咱们能够用新的观察者取代现有的观察者,主题不会收到任何影响。一样的,也能够在任什么时候候删除某些观察者

3、有新类型的观察者出现时,主题的代码不须要修改。假如咱们有个新的具体类须要当观察者,咱们不须要为了兼容新类型而修改主题的代码,全部要作的就是在新的类里实现此观察者接口,而后注册为观察者便可。主题不在意别的,它只会发送通知给全部实现了观察者接口的对象

4、咱们能够独立地复用主题或观察者。若是咱们在其余地方须要使用主题和观察者,能够轻易地复用,由于两者并不是紧耦合

5、改变主题或观察者其中一方,并不会影响另外一方。由于二者是松耦合的,因此只要他们之间的接口仍被遵循,咱们就能够自由地改变他们

6、设计原则——为了交互对象之间得松耦合设计而努力

7、松耦合的设计之因此能让咱们创建有弹性的OO系统,可以应对变化,是由于对象之间的互相依赖降到了最低

 

把观测值直接传入观察者中是更新状态的最直接的方法,你认为这样的作法明智吗?

这些观测值的种类和个数在将来有可能改变吗?若是之后会改变,这些变化是否被很好地封装?或者是须要修改许多代码才能办到?

关于将更新的状态传送给观察者,你可否想到更好的方法解决此问题?

 

围炉夜话:主题与观察者

主题:我很高兴,咱们终于有机会面对面聊天了

观察者:是这样吗?我觉得你根本不在意咱们这群观察者呢?

主题:哎呀!我把该作的事都作到了,不是吗?我老是会通知大家发生什么事了....我虽然不知道大家是谁,但这不意味着我不在意大家。何况,我知道关于大家的一件重要的事:大家实现了Observer接口

观察者:是呀,但只是关于个人一小部分罢了!不管如何,我对你更了解

主题:是吗?说来听听!

观察者:嗯!你老是将你的状态传给咱们,因此咱们能够知道你内部的状况。有时候,这很烦人的.....

主题:拜托,我必须主动送出个人状态和通知给你们,好让大家这些懒惰的观察者知道发生什么事了

观察者:咳!等等,我说主题先生,首先,咱们并不懒,在你那些"很重要"、通知的空档中,咱们还有别的事要作。另外,为什么由你主动送数据过来,而不是让咱们主动去向你索取数据?

主题:嗯——这样或许也行,只是我必须所以门户大开,让大家所有均可以进来取得大家须要的状态,这样太危险了。我不能让大家进来里面大肆挖掘个人各类数据

观察者:你何不提供一些公开的getter方法,让咱们“拉”走咱们须要的状态?

主题:是的,我可让大家“拉”走个人状态,可是你不以为这样大家反而不方便吗?若是每次想要数据时都来找我,你可能要调用不少次才能收集齐全你所要的状态。这就是为何我更喜欢"推的缘由,大家能够在一次通知中一口气获得全部东西

观察者:死鸭子嘴硬!观察者种类这么多,你不可能事先料到咱们每一个人的需求,仍是让咱们直接去取得咱们须要的状态比较恰当,这样一来,若是咱们有人只须要一点点数据,就不会被强迫收到一堆数据。这么作同时也能够在之后比较容易修改。比方说,哪一天你决定扩展功能,新增更多的状态,若是采用我建议的方式,你就不用修改和更新对每位观察者的调用,只需改变本身来容许更多的getter方法来取得新增的状态

主题:是的,两种作法都有各自的优势。我注意到Java内置的Observer模式两种作法都支持

观察者:真的吗?

主题:太好了,或许我会看到一个""的好例子,于是改变个人想法

 

使用Java内置的观察者模式

到目前为止,咱们已经从无到有地完成了观察者模式,可是,Java API有内置得观察者模式。java.util包(package)内包含最基本的Observer接口与Observable类,这和咱们的Subject接口与Observer接口很类似Observer接口与Observalbe类使用上更方便,由于许多功能都已经事先准备好了。你甚至可使用推(push)或拉(pull)的方式传送数据,稍后就会看到这样的例子。

有了Java内置的支持,你只须要扩展(继承)Observable,并告诉它什么时候该通知观察者,一切就完成了,剩下的事API会帮你作

 

setChanged()方法

setChanged()方法用来标记状态已经改变的事实,好让notifyObservers()知道当它被调用时应该更新观察者。若是调用notifyObservers()以前没有先调用setChanged(),观察者就“不会”被通知

1setChanged()方法把changed标志设为true

2notifyObservers()只会在changed标为"true"时通知观察者

3、在通知观察者以后,把changed标志社回false

这样作有其必要性,setChanged()方法可让你在更新观察者时,有更多的弹性,你能够更适当地通知观察者。比方说,若是没有setChanged()方法,咱们得气象站测试是如此敏锐,以致于温度计读书每十分之一度就会更新,这会形成WeatherData对象持续不断地通知观察者,咱们并不但愿看到这样的事情发生。若是咱们但愿半度以上才更新,就能够在温度差距到达半度时,调用setChanged(),进行有效的更新。

你也许不会常常用到此功能,可是把这样的功能准备好,当须要时立刻就可使用。总之,你须要调用setChanged(),以便通知开始运转。若是此功能在某些地方对你有帮助,你可能也须要clearChanged()方法,将changed状态设置回false。另外也有一个hasChanged()方法,告诉你changed标志的当前状态

 

不要依赖于观察者被通知的次序

1java.util.Observable实现了它的notifyObservers()方法,这致使了通知观察者的次序不一样于咱们先前的次序。谁也没有错,只是双方选择不一样的方式实现罢了

2、可是能够肯定的是,若是咱们的代码依赖这样的次序,就是错的。为何呢?由于一旦观察者/可观察者的实现有所改变,通知次序就会改变,极可能就会产生错误的结果,这绝对不是咱们所认为的松耦合

 

难道Java.util.Observable违反了咱们的OO设计原则:针对接口编程,而非针对实现编程?

java.util.Observable的黑暗面

1、是的,可观察者是一个“类”而不是一个“接口”,更糟糕的是,它甚至没有实现一个接口。不幸的是,java.util.Observable的实现有许多问题,限制了它的使用和复用。这并非说它没有提供有用的功能,咱们只是想提醒你们注意一些事实

2Observable是一个类,你已经从咱们的原则得知这不是一件好事,可是,这到底会形成什么问题呢?

3、首先,由于Observable是一个“类”,你必须设计一个类继承它。若是某类想同时具备Observable类和另外一个超类的行为,就会陷入两难,毕竟Java不支持多重继承,这限制了Observable的复用潜力(而增长复用潜力不正是咱们使用模式最原始的动机吗?)

4、再者,由于Observable接口,因此你没法创建本身的实现,和Java内置的ObserverAPI搭配使用,也没法将java.util的实现换成另外一套作法的实现(比方说,Observable将关键的方法保护起来,若是你看看ObservableAPI,你会发现setChanged()方法被保护起来了(被定义成protected),那又怎么样呢?这意味着:除非你继承自Observable,不然你没法建立Observable实例并组合到你本身的对象中来,这个设计违反了第二设计原则:"多用组合,少用继承"

5、若是你可以扩展java.util.Observable,那么Observable"可能"能够符合你的需求,不然,你可能须要像以前的方式本身实现这一整套观察者模式,无论用哪一种方法,反正你都已经熟悉观察者模式了

 

JDK中,还有哪些地方能够找到观察者模式

JDK中,并不是只有在java.util中次啊能找到观察者模式,其实在JavaBeansSwing中,也都实现了观察者模式。

 

OO原则

1、封装变化

2、多用组合,少用继承

3、针对接口编程,不针对实现编程

四、为交互对象之间的松耦合设计而努力

 

OO模式

观察者模式(Observer pattern)——在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新

 

要点

1、观察者模式定义了对象之间一对多的关系

二、主题(也就是可观察者)用一个共同的接口来更新观察者

三、观察者和可观察者之间用松耦合方式结合(loosecoupling),可观察值不知道观察者的细节,只知道观察者实现了观察者接口

四、使用此模式时,你可从被观察者处推(push)或拉(pull)数据(然而,推的方式被认为更“正确”)

五、有多个观察者时,不能够依赖特定的通知次序

六、Java有多种观察者模式的实现,包括了通用的java.util.Observable

七、要注意java.util.Observable实现上所带来的一些问题

八、若是有必要的话,能够实现本身的Observable,这并不难,不要惧怕

九、Swing大量使用观察者模式,许多GUI也是如此

十、此模式也被应用在许多地方,例如:JavaBeans、RMI


观察者的表明人物——MVC

 

观察者模式包含的OO设计原则

1、在观察者模式中,会改变的是主题的状态,以及观察者的数目和类型。用这个模式,你能够改变依赖于主题状态的对象,却没必要改变主题,这就叫提早规划

2、主题与观察者都使用接口:观察者利用主题的接口向主题注册,而主题利用观察者接口通知观察者,这样可让二者之间运做正常,又同时具备松耦合的优势

3、观察者模式利用“组合”将许多观察者组合进主题中,对象之间的这种关系不是经过继承产生的,而是在运行时利用组合的方式而产生的

相关文章
相关标签/搜索