什么是观察者模式
摘自百度的解释
观察者(Observer)模式又名发布-订阅(Publish/Subscribe)模式。GOF给观察者模式如下定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
观察者模式的优缺点
- 观察者模式的优点:
1.观察者模式实现了观察者和目标之间的耦合
2.观察者模式实现了动态联动
3.观察者模式支持广播通信 - 观察者模式的缺点:
1.可能会引起无谓的操作
比如说你想推送的消息,只给某个观察者,但此刻忘了删除其他的观察者,一经推送,其他观察者都收到了,这样就会产生比较麻烦的事情。
代码实现
经典的观察者模型
//Subject目标类
public class Subject{
//维护观察者
private List<Observer> observers = new ArrayList<Observer>();
//对观察者进行添加
public void attech(Observer observer){
observers.add(observer);
}
//对观察者进行删除
public void detech(Observer observer){
observers.add(observer);
}
//对每个观察者进行广播
protected void notifyObservers(){
for(Observer observer:observers){
observer.update(this);
}
}
}
//Observer观察者接口
public interface Observer{
public void update(Subject subject);
}
//Subject实现类,负责设置属性状态
public class ConcreteSubject extends Subject{
private String content;
public void setContent(String content){
this.content = content;
//当设置状态了,就需要对每个观察者进行广播,让他们及时更新消息
this.notifyObservers();
}
public String getContent(){
return content;
}
}
//观察者实现类
public class ConcreteObserver implements Observer{
//观察者的状态,负责接收subject目标发过来的状态
private String observerState;
//对update()进行实现
public void update(Subject subject){
}
}
现在将观察者放在一个场景中
比如说,我的女朋友和老妈很喜欢买衣服(不经意间暴露了嘿嘿…),然而她们在上网买衣服时觉得很麻烦,必须要花费很长时间来进行挑选,我做了一个软件把上网比较受欢迎的衣服消息同时推送给她们,这样就比较方便了。
下面我们来进行代码的实现吧!!
by the way现在我用的是观察者中的拉模型实现的,稍后我会介绍观察者模式中推模型和拉模型的区别
//目标对象类,负责维护女朋友和老妈这两个观察者
public class BuySubject{
private List<Observer> observers = new ArrayList<Observer>();
public void attech(Observer observer){
observers.add(observer);
}
public void detech(Observer observer){
observers.remove(observer);
}
//进行广播通知,非子类是不能得到该方法的
protected void notifyObservers(){
for(Observer observer:observers){
observer.update(this);
}
}
}
//Observer观察者接口
public interface Observer{
//将整个目标对象发给观察者,需要什么取什么(想拉什么拉什么),所以就是拉模型了
public void update(BuySubject subject);
}
//subject目标对象的实现
public class ConcreteBuySubject extends BuySubject{
//将衣服的信息放在此处,等会推送给观察者
private String clothesContent;
public void setClothesContent(String clothesContent){
this.clothesContent = clothesContent;
this.notifyObservers();
}
public String getClothesContent(){
return clothesContent;
}
}
//Observer观察者接口的实现
public class ConcreteObserver implements Observer{
//观察者的名称
private String observerName;
//观察者的状态,从subject接收过来的
private String clothesContent;
public void update(BuySubject subject){
clothesContent = ((ConcreteBuySubject)subject).getClothesContent();
System.out.println(observerName+"收到了"+clothesContent);
}
public void setObserverName(String observerName){
this.observerName = observerName;
}
public String getObserverName(){
return observerName;
}
}
//测试类
public class Test{
public static void main(String[] args){
//1.创建目标对象
ConcreteBuySubject subject = new ConcreteBuySubject();
//2.创建观察者
ConcreteObserver myGirl = new ConcreteObserver();
myGirl.setObserverName("我的女票");
ConcreteObserver myMum = new ConcreteObserver();
myMum.setObserverName("我的老妈");
//3.注册观察者
subject.attech(myGirl);
subject.attech(myMum);
//4.推送消息
subject.setClothesContent("爆款长裙,淘宝地址:https://taobao.com/...../");
}
}
同样,我们展示一下推模型
推模型就是不管消息你愿不愿意接收,我都发送给你。
//目标对象
public class BuySubject{
private List<Observer> observers = new ArrayList<Observer>();
public void attech(Observer observer){
observers.add(observer);
}
public void detech(Observer observer){
observers.remove(observer);
}
//此处加入了一个参数,用来传递想要发送的消息
public void notifyObservers(String content){
for(Observer observer:observers){
observer.update(content);
}
}
}
//Observer观察者接口
public interface Observer{
//接收的不再是对象,而是具体什么类型的消息
public void update(String content);
}
//目标对象实现类
public class ConcreteBuySubject extends BuySubject{
private String clothesContent;
public void setClothesContent(String clothesContent){
this.clothesContent = clothesContent;
this.notifyObservers(clothesContent);
}
}
//Observer实现类
public class ConcreteObserver implements Observer{
private String observerName;
private String clothesContent;
public void update(String content){
clothesContent = content;
}
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
}
Test类和拉模型是一样的,得到的结果也是相同的,但具体实现的方式是不同的。
在Java中本身也提供了观察者模式的接口,我们只要实现接口,就可以直接使用可以更加方便
//目标对象的具体实现类
public class ConcreteBuySubject extends Observable{
//推送衣服的内容
private String content;
public String getContent(){
return content;
}
public void setContent(String content){
this.content = content;
//进行通知前,必不可少的方法
this.setChanged();
//主动通知观察者,属于推模型
this.notifyObservers(content);
//如果是拉模型,直接把subject传过去
//this.notifyObservers();
}
}
//观察者的具体实现
public class ConcreteObserver implements Observer{
//观察者的名称,老妈,女朋友
private String observerName;
//第一个参数是传一个目标的引用过来,是拉模型
//第二个参数是传一个参数过来,是推模型
public void update(Observable o,Object arg){
//推模型
System.out.println(observerName+"收到了信息,推过来的是"+arg);
//拉模型
System.out.println(observerName+"收到了消息,主动到目标去拉,拉过来的是"+((ConcreteBuySubject)o).getContent());
}
public String getObserverName() {
return observerName;
}
public void setObserverName(String observerName) {
this.observerName = observerName;
}
}
观察者模式的高级实现
现在呢,我的女朋友对我又有了新的要求,她还想买鞋子,想让我把鞋子的信息也推送给她,但我老妈比较节俭,她就不要鞋子了,想省点钱。这个时候就不能把消息一股脑儿的全都推送给她们。需要按需分配消息了,这个时候该怎么实现呢?
//目标对象抽象类,用来管理观察者列表和广播消息
public abstract class BuySubject{
//用来管理观察者
private List<Observer> observers = new ArrayList<Observer>();
public void attech(Observer observer){
observers.add(observer);
}
public void detech(Observer observer){
observers.remove(observer);
}
//用来对观察者进行广播,设为抽象类,具体实现由子类来实现
public abstract void notifyObservers();
}
//观察者接口,具有更新方法,可以设置观察者名称
public interface Observer{
public void update(BuySubject subject);
public void setObserverName(String observerName);
public String getObserverName();
}
//目标对象的实现类,负责设置推送的消息,实现广播方法
public class ConcreteBuySubject extends BuySubject{
//设置状态,“衣服” “鞋子”
private String content;
public void notifyObservers(){
//循环观察者
for(Observer observer:observers){
if("衣服".equals(this.getContent())){
if("女朋友".equals(observer.getObserverName())){
observer.update(this);
}else if("老妈".equals(observer.getObserverName())){
observer.update(this);
}
}
if("鞋子".equals(this.getContent())){
if("女朋友".equals(observer.getObserverName())){
observer.update(this);
}
}
}
}
public String getContnt() {
return contnt;
}
public void setWeatherContnt(String contnt) {
this.contnt = contnt;
this.notifyObservers();
}
}
//实现观察者接口,从目标对象接收要购买衣服鞋子的消息
public class ConcreteObserver implements Observer{
//观察者的名字
private String observerName;
//内容“衣服”“鞋子”
private String content;
//设置商品的特点
private Sting specialThing;
public void update(BuySubject subject){
content = ((ConcreteBuySubject)subject).getContent();
System.out.println(observerName+"收到了"+content"内容的推送,"+specialThing);
}
public String getObserverName(){
return observerName;
}
public void setObserverName(String observerName){
this.observerName = observerName;
}
public String getSpecialThing(){
return specialThing;
}
public void setSpecialThing(){
this.specialThing = specialThing;
}
}
//测试类
public class Test{
public static void main(String[] args){
//1.实现目标对象
ConcreteBuySubject subject = new ConcreteBuySubject();
//2.建立观察者
ConcreteObserver myGirl = new ConcreteObserver();
myGirl.setObserverName("老妈");
myGirl.setSpecialThing("碎花长裙,劲爆5折");
ConcreteObserver myMum = new ConcreteObserver();
myMum.setObserverName("女朋友");
myMum.setSpecialThing("碎花长裙,劲爆5折;小牛皮休闲女鞋,一买双第二双半价");
//3.注册观察者
subject.attech();
subject.attech();
//4.推送消息
subject.setContent("衣服");
//subject.setContent("鞋子");
}
}
观察者模式就简单的介绍完毕了!希望大家都有自己的女朋友,真的给自己老妈和女票做个这样的软件方便她们买买买,剁剁剁~^_^!