}
public class ObserverTest {
public static void main(String[] args) {
MySubject mySubject = new MyConcreteSubject();
mySubject.reg(new MyObserverA());
mySubject.reg(new MyObserverB());
mySubject.reg(new MyObserverC());
Msg msg = new Msg();
msg.setId(1);
msg.setName(“小明”);
mySubject.notify(msg);
}
}
public class Msg {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String to 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 String() {
return “Msg{” +
“id=” + id +
“, name='” + name + ‘’’ +
‘}’;
}
}
上面就是一个简单的观察者模式模板,是不是很简单,没错,就是这么简单,我们一起来看看打印的结果是什么
我是:MyObserverA,我被执行了;执行参数:Msg{id=1, name=‘小明’}
我是:MyObserverB,我被执行了;执行参数:Msg{id=1, name=‘小明’}
我是:MyObserverC,我被执行了;执行参数:Msg{id=1, name=‘小明’}
Process finished with exit code 0
现在对观察者模式是不是有点理解了呢?那和上面的注册有什么关系呢?大家可以想一想,注册时候添加的消息推送、限时VIP赠送、保存手机号的归属地是不是刚好对应上面的MyObserverA、MyObserverB、MyObserverC,没错,我们可以将这三个功能与注册功能剥离,这样注册功能就会变得非常的简单,通过发布订阅的这种方式来告诉订阅的观察者们,你们需要执行了。
[](()注册功能改造
=====================================================================
看到上面的这个案例之后想必你应该知道怎么去改造注册的代码了吧,那我们就一起来看看注册这个功能。
原始写法
public class UserReg {
/**
-
注册,保存用户信息
-
@param user
*/
private void saveUser(User user){
System.out.println(“将用户信息保存到数据库中,注册成功!”);
}
/**
-
赠送限时VIp
-
@param user
*/
private void giveVip(User user){
System.out.println(“赠送限时VIp成功!”);
}
/**
-
发送使用指南的消息
-
@param user
*/
private void sendMsg(User user){
System.out.println(“给用户推送一条系统消息,消息的内容为用户指南!”);
}
/**
-
查询用户手机号码的归属地,保存到数据库
-
@param user
*/
private void savePhoneRegion(User user){
System.out.println(“查询用户手机号码的归属地,保存到数据库,方便发数据部门的同事做数据分析!”);
}
public void reg(User user){
//注册
saveUser(user);
//赠送限时VIp
giveVip(user);
//发送使用指南的消息
sendMsg(user);
//查询用户手机号码的归属地,保存到数据库
savePhoneRegion(user);
}
}
public class User {
/**
- 手机号
*/
private String phone;
/**
- 密码
*/
private String pwd;
public void setPhone(String phone) {
this.phone = phone;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return “User{” +
“phone='” + phone + ‘’’ +
“, pwd='” + pwd + ‘’’ +
‘}’;
}
}
public class UserTest {
public static void main(String[] args) {
UserReg userReg = new UserReg();
User user = new User();
user.setPhone(“18888888888”);
user.setPwd(“123456”);
userReg.reg(user);
}
}
运行main函数
将用户信息保存到数据库中,注册成功!
给用户推送一条系统消息,消息的内容为用户指南!
查询用户手机号码的归属地,保存到数据库,方便发数据部门的同事做数据分析!
Process finished with exit code 0
是不是实现了小明做的注册功能?是的,一点毛病都没有,但我不推荐这么写,你们知道为什么吗?现在只有三个,那后面还有新的功能呢?我们还继续在reg()方法中添加吗?这种很明显违反了设计原则中的单一原则,一个注册方法做了太多与注册无关的事情,所以我们需要将它们剥离,设计原则往往比设计模式更加的重要,所以我们一起使用观察模式改造一下这个注册功能。
public interface RegSubject {
/**
- 注册观察者
*/
void reg(MyRegObserver myRegObserver);
/**
- 删除观察者
*/
void detele(MyRegObserver myRegObserver);
/**
- 通知所有的观察者
*/
void notify(User user);
}
public class MyRegSubject implements RegSubject {
private List myObservers = new ArrayList();
@Override
public void reg(MyRegObserver myRegObserver) {
myObservers.add(myRegObserver);
}
@Override
public void detele(MyRegObserver myRegObserver) {
myObservers.remove(myRegObserver);
}
@Override
public void notify(User user) {
if(myObservers.size() > 0){
for (MyRegObserver observer: myObservers) {
observer.regHandler(user);
}
}
}
}
/**
- 观察者接口
*/
public interface MyRegObserver {
/**
-
做某些事
-
@param user
*/
void regHandler(User user);
}
public class MsgNotificationObserver implements MyRegObserver {
@Override
public void regHandler(User user) {
System.out.println(“给用户推送一条系统消息,消息的内容为用户指南!;执行参数:”+user);
}
}
/**
- 限时vip
*/
public class LimitVipObserver implements MyRegObserver {
@Override
public void regHandler(User user) {
System.out.println(“赠送限时VIp成功!执行参数:”+user);
}
}
/**
- 保存用户手机号归属地
*/
public class PhoneRegionObserver implements MyRegObserver {
@Override
public void regHandler(User user) {
System.out.println(“查询用户手机号码的归属地,保存到数据库,方便发数据部门的同事做数据分析!执行参数:”+user);
}
}
public class User {
/**
- 手机号
*/
private String phone;
/**
- 密码
*/
private String pwd;
public void setPhone(String phone) {
this.phone = phone;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return “User{” +
“phone='” + phone + ‘’’ +
“, pwd='” + pwd + ‘’’ +
‘}’;
}
}
public class UserReg {
/**
-
注册,保存用户信息
-
@param user
*/
private void saveUser(User user){
System.out.println(“将用户信息保存到数据库中,注册成功!”);
}
public void reg(User user){
//注册
saveUser(user);
RegSubject regSubject = new MyRegSubject();
regSubject.reg(new MsgNotificationObserver());
regSubject.reg(new LimitVipObserver());
regSubject.reg(new PhoneRegionObserver());
regSubject.notify(user);
}
}
public class UserTest {
public static void main(String[] args) {
UserReg userReg = new UserReg();
User user = new User();
user.setPhone(“18888888888”);
user.setPwd(“123456”);
userReg.reg(user);
}
}
执行main()函数
将用户信息保存到数据库中,注册成功!
给用户推送一条系统消息,消息的内容为用户指南!;执行参数:User{phone=‘18888888888’, pwd=‘123456’}
赠送限时VIp成功!执行参数:User{phone=‘18888888888’, pwd=‘123456’}
查询用户手机号码的归属地,保存到数据库,方便发数据部门的同事做数据分析!执行参数:User{phone=‘18888888888’, pwd=‘123456’}
Process finished with exit code 0
虽然已经将与注册无关的功能抽离了出来,但是还有一个问题没有解决,那就是需要在注册方法中new 观察者类,这点肯定会让很多开发者非常不爽,如果使用观察者模式需要这样new的话,还不如之前的写法呢,没错,在reg()方法中new观察者确实不是一个好办法,这个肯定是可以解决的,那你知道如何解决这个问题吗?
我们只需要将MyRegSubject中的方法移到UserReg类中,改造一下如下:
public class UserReg {
private List myObservers = new ArrayList();
/**
-
一次性将所有的观察者都添加进来
-
@param myObservers
*/
public void regAll(List myObservers) {
myObservers.addAll(myObservers);
}
/**
-
注册,保存用户信息
-
@param user
*/
private void saveUser(User user){
System.out.println(“将用户信息保存到数据库中,注册成功!”);
}
public void reg(User user){
//注册
saveUser(user);
for(MyRegObserver myRegObserver : myObservers){
myRegObserver.regHandler(user);
}
}
}
这样就是将观察者的管理交给了UserReg,那你可能就会有疑惑了,这样还不是需要在外部new?没错,虽然需要new,但是我可以在程序启动的时候通过注入的方式将这些观察者都注入到UserReg中,我们直接去ioc容器拿这个bean就可以了,后续的改动也仅仅只是需要修改对应的观察者,并不需要对注册的方法做修改,虽然还是违背开闭原则,但是这种写法可以大大的降低程序的bug,还是比较推荐的。
我和小明讲到这里的时候,他好像明白了,点了点头,随后又说了一句:大哥,能将这些观察者设置成异步的吗?我发现用户的注册并不需要这三个观察者的结果,如果能做成异步,那就会大大的提高注册的效率。握草,过分了啊,不过看着小明对知识的渴望,我就成全他吧,在给他上一课,什么叫:异步非阻塞观察者模式
.。
[](()异步非阻塞观察者模式
=========================================================================
是的,你没有听错,就是异步非阻塞观察者模式,什么意思呢?顾名思义,就是让观察者的执行异步,主线程的执行不受它们的执行影响。
如果只是一个很简单的观察者模式,直接在观察者方法中创建一个新的线程,这样它们的执行就是异步了,实现如下:
/**
- 限时vip
*/
public class LimitVipObserver implements MyRegObserver {