基于Java的设计模式-观察者模式

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

观察者模式主要是解决一个对象状态改变给其他对象通知的问题。总共分为四部分:

  • 抽象被观察者角色:抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。
  • 抽象观察者角色:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,在得到主题通知时更新自己。
  • 具体被观察者角色:具体的主题,在集体主题的内部状态改变时,所有订阅过的观察者发出通知。
  • 具体观察者角色:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。

实现

抽象观察者角色

public interface Observer {
	public void updateInfo(String message);
}

具体观察者角色

public class ManObserver implements Observer {

	@Override
	public void updateInfo(String message) {
		System.out.println("男士接受的信息:"+message);
	}
}


=====


public class WomanObserver implements Observer {

	@Override
	public void updateInfo(String message) {
		System.out.println("女士接受的信息:"+message);
	}

}

抽象被观察者角色

public interface SubInfoService {
	//发送消息
	public void subMessage(String message);
	//订阅
	public void addObservers(Observer observer);
	//取消订阅
	public void cancerObservers(Observer observer);
}

具体被观察者角色

import java.util.ArrayList;
import java.util.List;

public class SubInfo implements SubInfoService{
	private List<Observer> observers; 
	
	private String message;
	
	public SubInfo(){
		observers = new ArrayList<Observer>();
	}
	//发布信息
	public void subMessage(String message){
		this.message=message;
		notifyAllObserver();
	}
	//订阅
	public void addObservers(Observer observer){
		observers.add(observer);
	}
	
	//每个订阅者都发布信息
	public void notifyAllObserver(){
		for (Observer observer : observers) {
			observer.updateInfo(message);
		}
	}
	//取消订阅
	@Override
	public void cancerObservers(Observer observer) {
		observers.remove(observer);
	}
}

测试

public class TestSub {
	public static void main(String[] args) {
		WomanObserver wo = new WomanObserver();
		ManObserver mo = new ManObserver();
		SubInfo sub = new SubInfo();
		sub.addObservers(mo);
		sub.addObservers(wo);
		sub.subMessage("信息来了");
		System.out.println("=======");
		sub.subMessage("你们好啊!");
		System.out.println("=======");
		sub.cancerObservers(wo);
		sub.subMessage("我们聊聊");
	}
}

结果

男士接受的信息:信息来了
女士接受的信息:信息来了
=======
男士接受的信息:你们好啊!
女士接受的信息:你们好啊!
=======
男士接受的信息:我们聊聊

这个观察者模式优点就是观察者和被观察者是抽象耦合的。缺点就是当订阅者过多的时候,所有观察者通知会花费很多时间。如果观察者和被观察者之间循环调用就会使得系统崩溃。

在Spring的事件机制中就体现了观察者模式。

我在SSM的项目实现这样的功能,当用户注册的时候,发送一封邮件给该用户。

EmailEvent.java

import org.springframework.context.ApplicationEvent;

public class EmailEvent extends ApplicationEvent{

	private static final long serialVersionUID = -5948806306069839382L;

	private String emailAddress;
	public EmailEvent(String emailAddress) {
		super(emailAddress);
		this.emailAddress =emailAddress;
	}
	public String getEmailAddress() {
		return emailAddress;
	}
	public void setEmailAddress(String emailAddress) {
		this.emailAddress = emailAddress;
	}	
}

EmailEventListener.java

import org.simplejavamail.email.Email;
import org.simplejavamail.email.EmailBuilder;
import org.simplejavamail.mailer.Mailer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class EmailEventListener implements ApplicationListener<EmailEvent> {

	private static Logger log = LoggerFactory.getLogger(EmailEventListener.class);
	
	@Autowired
	private Mailer mailer;
	
	@Value("${user.email.name}")
	private String emailName;
	
	@Override
	public void onApplicationEvent(EmailEvent event) {
		String email = event.getEmailAddress();
		log.info("事件监听,获取到注册邮件是:"+email);
		
		//发送邮件
		Email em = EmailBuilder.startingBlank()
		          .from("商家",emailName)  
				  .to("用户", email)
		          .withSubject("请查收你的邮件")
		          .withPlainText("非常感谢你的注册,快来逛一逛我们网站吧")
		          .buildEmail();
		 
	
		mailer.sendMail(em);
	}

}

EmailEventPublish.java

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;

@Component
public class EmailEventPublish implements ApplicationEventPublisherAware{

	private ApplicationEventPublisher applicationEventPublisher;
	
	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
		this.applicationEventPublisher=applicationEventPublisher;
	}
	
	public void publish(String email){
		EmailEvent event = new EmailEvent(email);
		applicationEventPublisher.publishEvent(event);
	}
}

applicationContext.xml

	<context:component-scan base-package="com.plf" />

UserController.java

@Autowired    
private ApplicationContext applicationContext;  

public String register(User user){
	...
	applicationContext.publishEvent(new EmailEvent(user.getEmail()));
	...
}
相关推荐
这孩子叫逆10 分钟前
Spring Boot项目的创建与使用
java·spring boot·后端
星星法术嗲人14 分钟前
【Java】—— 集合框架:Collections工具类的使用
java·开发语言
一丝晨光32 分钟前
C++、Ruby和JavaScript
java·开发语言·javascript·c++·python·c·ruby
天上掉下来个程小白35 分钟前
Stream流的中间方法
java·开发语言·windows
刷帅耍帅1 小时前
设计模式-享元模式
设计模式·享元模式
xujinwei_gingko1 小时前
JAVA基础面试题汇总(持续更新)
java·开发语言
liuyang-neu1 小时前
力扣 简单 110.平衡二叉树
java·算法·leetcode·深度优先
刷帅耍帅1 小时前
设计模式-模版方法模式
设计模式
一丝晨光1 小时前
Java、PHP、ASP、JSP、Kotlin、.NET、Go
java·kotlin·go·php·.net·jsp·asp
罗曼蒂克在消亡1 小时前
2.3MyBatis——插件机制
java·mybatis·源码学习