观察者模式,又称发布-订阅(Publish/Subscribe)模式,当对象间存在一对多关系,并且一个对象的状态被其他多个对象关注(该对象状态的改变对其他对象有影响)时,可以使用该模式。特点是:一个对象(目标对象)的状态发生改变,进行广播通知所有的依赖对象(观察者对象)。以明星和粉丝为例(不一定十分恰当),明星就是主题发布者,粉丝们就是订阅者;明星的粉丝关注数(粉丝集合),就像是主题发布者持有订阅者(观察者)的集合;明星有了新动态发条微博广播,所有关注她的粉丝都会被通知,不同的粉丝对该消息进行不同的响应。我是一个张韶涵粉丝,下面上代码:
package com.xfkj.observerPatten;
/**
* 主题发布接口
*/
public interface ISubject {
void attach(IObserver iObserver);
void dettach(IObserver iObserver);
void notifyObservers();
}
package com.xfkj.observerPatten;
import java.util.ArrayList;
import java.util.List;
/**
* 某个主题发布者
*/
public class Subject implements ISubject {
private List<IObserver> observers=new ArrayList<>();
private String state;
public List<IObserver> getObservers() {
return observers;
}
public void setObservers(List<IObserver> observers) {
this.observers = observers;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Override
public void attach(IObserver iObserver) {
observers.add(iObserver);
}
@Override
public void dettach(IObserver iObserver) {
observers.remove(iObserver);
}
@Override
public void notifyObservers() {
for (IObserver observer:observers) {
observer.update();
}
}
}
package com.xfkj.observerPatten;
/**
* 观察者接口
*/
public interface IObserver {
void update();
}
package com.xfkj.observerPatten;
/**
* 抽象观察者
*/
public class AbstractObserver {
private String observerName;
private String observerState;
private Subject subject;
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
public String getObserverState() {
return observerState;
}
public void setObserverState(String observerState) {
this.observerState = observerState;
}
public Subject getSubject() {
return subject;
}
public void setSubject(Subject subject) {
this.subject = subject;
}
}
package com.xfkj.observerPatten;
/**
*观察者之一
*/
public class Observer extends AbstractObserver implements IObserver {
public Observer(Subject subject,String observerName){
this.setObserverName(observerName);
this.setSubject(subject);
}
@Override
public void update() {
watchConcert();
}
private void watchConcert(){
this.setObserverState(this.getSubject().getState());
System.out.println(this.getObserverName()+"观察到"+this.getObserverState()+"->决定去看");
}
}
package com.xfkj.observerPatten;
/**
* 另外一个观察者
*/
public class AnotherObserver extends AbstractObserver implements IObserver {
public AnotherObserver(Subject subject,String observerName){
this.setObserverName(observerName);
this.setSubject(subject);
}
@Override
public void update() {
notWatchConcert();
}
private void notWatchConcert() {
this.setObserverState(this.getSubject().getState());
System.out.println(this.getObserverName()+"观察到"+this.getObserverState()
+"->跟我没关系决定不去看");
}
}
package com.xfkj.observerPatten;
/*
程杰老师的《大话设计模式》里讲到观察者模式的缺点是各个实现类的方法签名未必都一致,所以在Subject里统一调用update()方法
时会呈现一定的弊端,书中采用C#中的事件委托机制,来化解这个问题。其实也不然,不必要如此费周折。23种设计模式抛开具体应用场景
,核心的问题是解耦。世上本无事;如果存在理想的需求不变模型,那根据奥卡姆剃刀原理,能用最少的类就用最少的类;而现实
是需求是不断变化的,为了应对这种变化,对于那种具有变化风险同时又承担着“牵一发而动全身”的类,就需要解耦和;所谓牵一发而
动全身,是因为它的业务频繁,被多个类依赖,但需求变化的粒度是粗细不定的,为了单方面满足某个需求而改动被多处依赖调用的类,
就会波及其他调用者,毕竟事物是普遍联系的。因此,为了应对可能性的变化,需要通过抽象类、接口来隔离变化,依赖抽象而不依赖具体。
矛盾是一把双刃剑,一面它带来问题,另一面就是问题的答案。耦合是因为两个类联系太紧密了,而解耦恰恰就是反其道而行之。由此诞生了一
个伟大的思想“计算机中任何问题,都可以添加一个中间层来解决”,遗憾的是,这句名言的出处无从考证。从这个意义上来说,23种设计模式
再往上抽象就是中间件思想,而且模式各自结构也有相似之处。这就像金庸的武侠小说里提倡的“无招胜有招”的境界,在功底扎实之后,23种设计模式
即使记不全,记住中间件这个无上心法也知道该怎么施展拳脚——随机应变。
如果说接口是类级别的中间件,那么本例中接口的各自实现类在复写的方法里调用私有方法,就是方法级的
中间件。所谓“其大无外,其小无内”,再细还能到变量级别,例如全局容器变量;再大还能大到模块、架构层面等。
*/
public class TestObserverPatten {
public static void main(String[] args) {
Subject subject=new Subject();
IObserver observer=new Observer(subject,"真粉丝");
IObserver observer2=new AnotherObserver(subject,"假粉丝");
subject.attach(observer);
subject.attach(observer2);
subject.setState("张韶涵演唱会即将开始");
subject.notifyObservers();
}
}
运行结果:
真粉丝观察到张韶涵演唱会即将开始->决定去看
假粉丝观察到张韶涵演唱会即将开始->跟我没关系决定不去看