目录
一、基本概念
二、UML类图
三、角色设计
四、代码实现
案例一
案例二
案例三
五、总结
一、基本概念
观察者先订阅被观察者对象,当被观察者的状态发生变化时,观察者可以及时收到消息,在这种模式当中,被观察者维护了一个观察者列表,并提供了添加、删除、通知观察者的方法。
二、UML类图
三、角色设计
角色 | 描述 |
---|---|
Blogger | 被观察者接口(博主),内部提供了注册、删除、通知观察者的方法 |
CSDNBlogger | 具体被观察者对象接口的实现类(CSDN),内部维护一个观察者列表 |
Fans | 观察者接口(粉丝),在被观察者通知时更新自己 |
FansObserver | 具体的观察者,当被通知时,可根据实际需求决定如何更新自己的状态 |
四、代码实现
这边我分享了三个案例,分别是通过自定义撰写、JDK源码封装和Spring框架封装三种去实现。
案例一
假设有一个被观察者:CSDN博主,它有2个粉丝分别是Jack和Tom,当CSDN发布了通知,对应的粉丝都会收到私信。
1、定义被观察者接口。
public interface Blogger {/*** 新增粉丝*/void addFans(Fans fans);/*** 移除粉丝*/void removeFans(Fans fans);/*** 通知粉丝*/void sendMessage(String message);
}
2、被观察者具体实现类。
CSDN博主:
import java.util.ArrayList;
import java.util.List;public class CSDN implements Blogger {private List<Fans> fansList = new ArrayList<>();@Overridepublic void addFans(Fans fans) {this.fansList.add(fans);}@Overridepublic void removeFans(Fans fans) {this.fansList.remove(fans);}@Overridepublic void sendMessage(String message) {for(Fans fans : fansList){fans.receiveMessage(message);}}
}
3、定义观察者接口。
public interface Fans {void receiveMessage(String message);}
4、定义具体观察者实现类。
Jack粉丝:
public class JackFans implements Fans {@Overridepublic void receiveMessage(String message) {System.out.println("Jack收到了私信:"+message);}
}
Tom粉丝:
public class TomFans implements Fans {@Overridepublic void receiveMessage(String message) {System.out.println("Tom收到了私信:"+message);}
}
5、测试运行:
public class Main {public static void main(String[] args) {Blogger blogger = new CSDN();Fans jackFans = new JackFans();Fans tomFans = new TomFans();blogger.addFans(jackFans);blogger.addFans(tomFans);blogger.sendMessage("CSDN发布了《关于社区整顿的通知》");blogger.removeFans(jackFans);blogger.sendMessage("CSDN发布了《关于博客发布调整的通知》");}
}
6、运行结果:
案例二
这个案例依旧是实现上述逻辑,只不过我们使用JDK提供的接口去实现,过程如下。
1、定义被观察者具体实现类。
CSDN博主:
import java.util.Observable;public class CSDN extends Observable {@Overridepublic void notifyObservers(Object arg) {//修改状态为可以群发setChanged();//调用父类的notifyObservers 群发消息super.notifyObservers(arg);}
}
2、定义观察者具体实现类。
Tom粉丝:
import java.util.Observable;
import java.util.Observer;public class TomFans implements Observer {@Overridepublic void update(Observable o, Object arg) {System.out.println("Tom收到了私信:"+arg);}
}
Jack粉丝:
import java.util.Observable;
import java.util.Observer;public class JackFans implements Observer {@Overridepublic void update(Observable o, Object arg) {System.out.println("Jack收到了私信:"+arg);}
}
3、测试运行:
import java.util.Observable;
import java.util.Observer;public class Main {public static void main(String[] args) {Observable csdn = new CSDN();Observer tomFans = new TomFans();Observer jackFans = new JackFans();csdn.addObserver(tomFans);csdn.addObserver(jackFans);csdn.notifyObservers("《关于整顿社区的通知》");csdn.deleteObserver(tomFans);csdn.notifyObservers("《关于更新CSDN社区的通知》");}
}
4、运行结果:
有了JDK提供的接口去实现,整体代码结构更简洁和方便了!
案例三
这个案例依旧是上述逻辑,只不过我们这边使用Spring提供的封装事件的监听去实现,这边省去了搭建Spring框架的流程,直接看核心代码就行!
ApplicationEvent和Listener实际上就是Spring基于观察者模式设计的发布-订阅事件模型。
1、ApplicationEvent :自定义的事件对象,用于表示具体的事件。
CSDN博主:
import org.springframework.context.ApplicationEvent;public class CSDN extends ApplicationEvent {private String message;public CSDN(Object source,String message) {super(source);this.message = message;}public String getMessage(){return this.message;}public void setMessage(String message){this.message = message;}}
2、ApplicationListener:事件监听器接口,用于监听特定事件。
Jack粉丝:
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class JackFans implements ApplicationListener<CSDN> {@Overridepublic void onApplicationEvent(CSDN event) {System.out.println("Jack收到私信:"+event.getMessage());}
}
Tom粉丝:
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class TomFans implements ApplicationListener<CSDN> {@Overridepublic void onApplicationEvent(CSDN event) {System.out.println("Tom收到私信:"+event.getMessage());}
}
3、单元测试
ApplicationContext:Spring上下文,用于广播ApplicationEvent,并通知相关的ApplicationListener。
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;import javax.annotation.Resource;@SpringBootTest
class ObserverApplicationTests {@Resourceprivate ApplicationContext applicationContext;@Testvoid contextLoads() {CSDN csdn = new CSDN(this,"发布了《关于整顿社区的通知》");applicationContext.publishEvent(csdn);}}
4、运行结果
通过这种方式,不同的业务逻辑模块就可以不依赖于具体的实现,只通过监听特定事件来响应,从而实现解耦。
事件驱动的编程方式还有以下优点:
1、降低耦合度
2、提高模块间的独立性和可重用性
3、易于扩展和维护
总的来说,ApplicationEvent和Listener的设计初衷就是为了解耦和提高系统的扩展性、稳定性。
五、总结
这边我举了3个案例去更好的理解观察者模式,在我们日常开发的工作中要时刻提醒我们自己的编码思想,利用好这些优秀的前辈提供给我们的精髓,应用到实际业务场景中去,精益求精!