注:源码及见解参见慕课网
第一节
1.官方定义:
定义对象间的一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
2.观察者模式的结构:
Subject | Observer |
---|---|
+Attach(o:Observer) | +Update( ) |
+Detach(o:Observer) | |
+Notify( ) |
3.标准模板
Subject.java
import java.util.ArrayList;
import java.util.List;
public class Subject {
//保护注册的观察者对象
private List observers = new ArrayList();
public void attath(Observer observer){
observers.add(observer);
}
public void detach(Observer observer){
observers.remove(observer);
}
protected void notifyObservers(){
for(Observer observer:observers){
observer.update(this);
}
}
}
Observer.java
public interface Observer {
public void update(Subject subject);
}
ConcreteSubject.java
public class ConcreteSubject extends Subject {
/*目标对象的状态*/
private String subjectState;
public String getSubjectState() {
return subjectState;
}
/*通知观察者*/
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
this.notifyObservers();
}
}
ConcreteObserver.java
public class ConcreteObserver implements Observer {
/*观察者的状态*/
private String observerState;
public void update(Subject subject) {
observerState = ((ConcreteSubject)subject).getSubjectState();
}
}
4.实例
weather.java
import java.util.ArrayList;
import java.util.List;
public class Weather {
//创建观察者列表
private List people = new ArrayList();
//添加观察者
public void attath(People people){
this.people.add(people);
}
//删除观察者
public void detach(People people){
this.people.remove(people);
}
//通知观察者更新
protected void updata(){
for(Peoplehuman:people){
human.updata(this);
}
}
}
TodayWeather.java
public class ConcreteObserver implements Observer {
//观察者的状态
private String observerState;
public void update(Subject subject) {
observerState = ((ConcreteSubject)subject).getSubjectState();
}
}
People.java
public interface People {
//创建更新的接口
public void updata(Weather weather);
}
ConcretePeople.java
public classConcretePeople implements People{
private String infromation;
private String name;
private String talk;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTalk() {
return talk;
}
public void setTalk(String talk) {
this.talk = talk;
}
@Override
public void updata(Weather weather) {
infromation = ((TodayWeather)weather).getWeatherContext();
System.out.println(name+"说:今天"+infromation+talk);
}
}
Test.java
public class Test {
public static void main(String[] args) {
ConcretePeople man = new ConcretePeople();
man.setName("小强");
man.setTalk("以该出去踢球");
ConcretePeople woman = new ConcretePeople();
woman.setName("小红");
woman.setTalk("应该去逛街");
TodayWeather todayWeather = new TodayWeather();
todayWeather.setWeatherContext("天气晴朗,蓝天白云,没有雾霾!!");
man.updata(todayWeather);
woman.updata(todayWeather);
}
}
输出结果:
小强说:今天天气晴朗,蓝天白云,没有雾霾!!以该出去踢球
小红说:今天天气晴朗,蓝天白云,没有雾霾!!应该去逛街
第二节
上一节里,我书写了观察者模式的模板和例子,
这一次我要再次深入的介绍观察者模式的两种方式和java自己封装好的观察者结构。
1.实现的两种方式:
推模型和拉模型
推模型:目标对象主动向观察者推送目标的详细信息,推送的信息通常是目标对象的全部或部分数据。
拉模型:目标对象在通知观察者的时候,只传递少量信息。
如果观察者需要更具体的信息,由观察者主动到目标对象中获取,相当于是观察者从目标对象中拉数据。
一般这种模型的实现中,会把目标对象自身通过update方法传递给观察者。
对于拉模型,上次一文中介绍的模板和例子均是采用的拉模型。下面我为大家修改上次的例子变成推模型。
Weather.java
import java.util.ArrayList;
import java.util.List;
public class Weather {
//创建观察者列表
private List people = new ArrayList();
//添加观察者
public void attath(People people){
this.people.add(people);
}
//删除观察者
public void detach(People people){
this.people.remove(people);
}
//通知观察者更新
protected void updata(String content){
for(Peoplehuman:people){
human.updata(content);
}
}
}
TodayWeather.java
public class TodayWeather extends Weather{
//今日天气
private String weatherContext;
public String getWeatherContext**() {
return weatherContext;
}
public void setWeatherContext(String weatherContext) {
this.weatherContext = weatherContext;
this.updata(weatherContext);
}
People.java
public interface People {
//创建更新的接口
public void updata(String content);
}
ConcreteWeather.java
public class ConcretePeople implements People{
private String infromation;
private String name;
private String talk;
public String getName() {
return name;
}
public void setName**(String name) {
this.name = name;
}
public String getTalk() {
return talk;
}
public void setTalk(String talk) {
this.talk = talk;
}
@Override
public void updata(String content) {
infromation = content;
System.out.println(name+"说:今天"+infromation+talk);
}
}
Test.java
public class Test {
public static void main(String[] args) {
ConcretePeople man = new ConcretePeople();
man.setName("小强");
man.setTalk("以该出去踢球");
ConcretePeople woman = new ConcretePeople();
woman.setName("小红");
woman.setTalk("应该去逛街");
TodayWeather todayWeather = new TodayWeather();
todayWeather.setWeatherContext("天气晴朗,蓝天白云,没有雾霾!!");
man.updata(todayWeather.getWeatherContext());
woman.updata(todayWeather.getWeatherContext());
}
}
输出结果:
小强说:今天天气晴朗,蓝天白云,没有雾霾!!以该出去踢球
小红说:今天天气晴朗,蓝天白云,没有雾霾!!应该去逛街
2.推拉模型的比较
Weather.java
import java.util.Observable;
public class Weather extends Observable{
private String WeatherContent;
public String getWeatherContent() {
return WeatherContent;
}
public void setWeatherContent(String weatherContent) {
WeatherContent = weatherContent;
//下面这句话在调用java里的Observer时必不可少
this.setChanged();
//这是拉模型没有参数
this.notifyObservers();
//这是推模型带参数
this.notifyObservers(weatherContent);
}
}
People.java
import java.util.Observable;
public class Weather extends Observable{
private String WeatherContent;
public String getWeatherContent() {
return WeatherContent;
}
public void setWeatherContent(String weatherContent) {
WeatherContent = weatherContent;
//下面这句话在调用java里的Observer时必不可少
this.setChanged();
//这是拉模型没有参数
this.notifyObservers();
//这是推模型带参数
this.notifyObservers(weatherContent);
}
}
Test.java
public class Test {
public static void main(String[] args) {
Weather weather = new Weather();
weather.setWeatherContent("今天天气晴朗,蓝天白云!!");
People man = new People();
man.setName("小明");
man.setTalk("我去踢球");
People woman = new People();
woman.setName("小红");
woman.setTalk("我要逛街");
man.update(weather, weather.getWeatherContent());
woman.update(weather, weather.getWeatherContent());
}
}
输出结果:
小明说:今天天气晴朗,蓝天白云!!,我去踢球推模式
小明说:今天天气晴朗,蓝天白云!!,我去踢球拉模式
小红说:今天天气晴朗,蓝天白云!!,我要逛街推模式
小红说:今天天气晴朗,蓝天白云!!,我要逛街拉模式
第三节
1.区别对待观察者场景问题:
最后一个问题,就是判断性的添加观察者。实现方法很简单,将subject这个类中的notifyChange()这个方法让其不去实现,使其在他的派生类中实现,(这样我们不妨把subject这个类作为抽象类,然后将notufyChange()这个方法作为抽象方法让其在子类中实现方法)然后就是在concretesubject()中在notifyChange()来判断那个对象可以做更新。(注:这里的方法名均为第一篇文章中模板的名字,和下面的例子不同)。
Weather.java
import java.util.ArrayList;
import java.util.List;
public abstract class Weather {
public List People humans = new ArrayListPeople();
public void attach(People people){
humans.add(people);
}
public void detach(People people){
humans.remove(people);
}
public abstract void notifyWeather();
}
Today.java
public class Today extends Weather{
private String weatherContent;
public void notifyWeather() {
for(People human:humans){
if(weatherContent.equals("下雨")){
if(human.getPeopleName().equals("小红")){
human.updata(this);
}
}
if(weatherContent.equals("下雪")){
if(human.getPeopleName().equals("小明")){
human.updata(this);
}
}
}
}
public String getWeatherContent() {
return weatherContent;
}
public void setWeatherContent(String weatherContent) {
this.weatherContent = weatherContent;
this.notifyWeather();
}
}
People.java
public interface People {
public void updata(Weather weather);
public void setPeopleName(String name);
public String getPeopleName();
}
Human.java
public class Human *implements People{
private String name;
public String getTalk() {
return talk;
}
public void setTalk(String talk) {
this.talk = talk;
}
public String getWeatherContent() {
return weatherContent;
}
private String talk;
private String weatherContent;
@Override
public void updata(Weather weather) {
System.out.println(name+"说:"+((Today)weather).getWeatherContent()+talk);
}
@Override
public void setPeopleName(String name) {
this.name = name;
}
@Override
public String getPeopleName**() {
return this.name;
}
}
Test.java
public class Test {
public static void main(String[] args) {
Today today = new Today();
Human man = new Human();
man.setPeopleName("小明");
man.setTalk("我要看雪");
Human woman = new Human();
woman.setPeopleName("小红");
woman.setTalk("下雨了不去了");
today.attach(man);
today.attach(woman);
today.setWeatherContent("下雪");
}
}
输出结果:
小明说:下雪我要看雪