基于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()));
	...
}
相关推荐
cdut_suye5 分钟前
Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试
java·linux·运维·服务器·c++·人工智能·python
苹果醋317 分钟前
2020重新出发,MySql基础,MySql表数据操作
java·运维·spring boot·mysql·nginx
小蜗牛慢慢爬行18 分钟前
如何在 Spring Boot 微服务中设置和管理多个数据库
java·数据库·spring boot·后端·微服务·架构·hibernate
azhou的代码园21 分钟前
基于JAVA+SpringBoot+Vue的制造装备物联及生产管理ERP系统
java·spring boot·制造
捕鲸叉30 分钟前
C++软件设计模式之外观(Facade)模式
c++·设计模式·外观模式
小小小妮子~1 小时前
框架专题:设计模式
设计模式·框架
先睡1 小时前
MySQL的架构设计和设计模式
数据库·mysql·设计模式
wm10431 小时前
java web springboot
java·spring boot·后端
smile-yan1 小时前
Provides transitive vulnerable dependency maven 提示依赖存在漏洞问题的解决方法
java·maven
老马啸西风1 小时前
NLP 中文拼写检测纠正论文-01-介绍了SIGHAN 2015 包括任务描述,数据准备, 绩效指标和评估结果
java