观察者模式

定义:当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。


介绍


意图:

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

主要解决:

一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

何时使用:

一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

如何解决:

使用面向对象技术,可以将这种依赖关系弱化。关键代码:在抽象类里有一个 ArrayList 存放观察者们。

应用实例:

在正式进入该设计模式之前,我想问一下:你们平常都用微信干什么呢?
“聊天”“发朋友圈”"“逛微店”“看微信公众号,关注自己喜欢的内容”
好嘲,就从微信公众号入手!平常我们关注一个微信公众号,当它推送新内容时,手机界面上就会出现一个红色的小点提醒我们查看详细内容。换句话说:我们订阅了公众号,当它有新消息时就会自动告知我们。也就是说:我们自己是观察者,在观察微信公众号,微信公众号就是被观察者。

优点:

1、观察者和被观察者是抽象耦合的。
2、建立一套触发机制。

缺点:

1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

使用场景:
  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
注意事项:

1、JAVA 中已经有了对观察者模式的支持类。
2、避免循环引用。
3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。


观察者模式的主要角色

  • 抽象主题(Subject):该角色为抽象目标类(或接口),它是一个被观察者。该角色提供增加、删除观察者 对象的抽象方法,以及通知所有观察者的抽象方法。
  • 具体主题(Concrete Subject):该角色是抽象主题(被观察者)的具体实现。
  • 抽象观察者(Observer):该角色是一个抽象类或接口,在该角色中包含接收到主题消息时的响应方法。
  • 具体观察者(Concrete Observer):该角色是抽象观察者的具体实现。

观察者模式实例

在此,以微信公众号为例来阐述观察者模式

抽象观察者

package com.zsn03.observer;

/*

 * 抽象观察者:该角色是一个抽象的接口或类

 *         包含接收到主题消息时的响应方法

 */

public interface Observer {
    public void receiveMessage(String message);         //收消息
}

具体观察者

package com.zsn03.observer;

/*

 * 具体观察者:是抽象观察者的具体实现类

 * 这里是用户

 */

public class ObserverImpl implements Observer{

    private String name;  //用户名

    public ObserverImpl(String name) {

       super();

       this.name = name;

    }

    public ObserverImpl() {

       super();
    }
    
    public String getName() {
       return name;
    }

    public void setName(String name) {

       this.name = name;

    }


    //用户接受信息
    @Override
    public void receiveMessage(String message) {
       System.out.println(name+", 收到消息:"+message);      
    }
}

抽象主题

package com.zsn03.observer;

/*

 * 抽象主题:抽象的目标类或者接口,他是被观察者,

 * 该角色提供增加,删除观察者对象的抽象方法,以及通知所有观察者的抽象方法

 * 例子:这是个微信公众号

 */

public interface Subject  {
    public void addObserver(Observer observer);        //添加观察者

    public void deleteObserver(Observer observer);     //删除观察者

    public void sendMessage(String messager);        //推送消息

}

抽象的主题(被观察者)的常用方法:添加观察者,删除观察者,发型消息。

具体主题

package com.zsn03.observer;
import java.util.ArrayList;
import java.util.Iterator;
/*
 * 具体主题:是被观察者的具体实现类
 * 这里是微信公众号
 */
public class SubjectImpl implements Subject{
	//把用户用ArrayList的集合存储
	private ArrayList<Observer> observerArrayList = new ArrayList<>(); 
	
	public SubjectImpl(ArrayList<Observer> observerArrayList) {
		super();
		this.observerArrayList = observerArrayList;
	}

	public SubjectImpl() {
		super();
		
	}
    
    //添加用户
	@Override
	public void addObserver(Observer observer) {
		if(observer!=null) {
			observerArrayList.add(observer);
		}
	}

    //删除用户
	@Override
	public void deleteObserver(Observer observer) {
		if(observer!=null) {
			observerArrayList.remove(observer);
		}	
	}
    
    //给用户推送消息
	@Override
	public void sendMessage(String messager) {
		if(messager!=null) {
			Iterator<Observer> iterator = observerArrayList.iterator();
			while(iterator.hasNext()) {
				Observer hasNext = iterator.next();
				hasNext.receiveMessage(messager);
			}
		}
	}
}

测试

package com.zsn03.observer;

/*

 * 测试用户是否全能收到消息

 */

public class Test {

    public static void main(String[] args) {

       //微信公众号

       SubjectImpl sub = new SubjectImpl(); 

       //用户

       Observer observer1 = new ObserverImpl("诸葛青");

       Observer observer2 = new ObserverImpl("张楚岚");

       Observer observer3 = new ObserverImpl("王也");


        //将用户添加到微信公众号中
       sub.addObserver(observer1);

       sub.addObserver(observer2);

       sub.addObserver(observer3);
      
       //设置推送信息
       sub.sendMessage("公众号内容更新:你喜欢的jk小姐姐上线了!!");
    }
}

测试结果

在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐