行为模式包含:观察者模式,模板方法模式,策略模式,职责链模式,状态模式,命令模式,中介者模式,迭代器模式,访问者模式,备忘录模式,解释器模式。
1.观察者模式的定义
定义对象之间一对多依赖关系,这样当一个对象改变状态时,他的所有依赖项都会自动得到通知和更新;
1.1 观察者模式的优缺点
优点
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系;
- 被观察者发送通知,所有注册的观察者都会收到信息;
缺点
- 如果观察者很多的话,所有的观察者收到被观察者发送的通知会耗时;
- 如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃;
1.2 观察者模式的使用场景
- 当一个对象状态的改变需要改变其他对象时,如商品库存数量发生变化需要通知商品详情页、购物车等系统改变数量;
- 发布订阅的场景,如微信公众号、微博、b站等,发布者发布内容,通知便会发送到关注者;
- 需要创建一种链式触发机制时,如在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象,这样通过观察者模式能够很好的实现;
- 需要建立基于事件触发的场景,如基于 Java UI 的编程,所有键盘和鼠标事件都由它的侦听器对象和指定函数处理。当用户单击鼠标时,订阅鼠标单击事件的函数将被调用,并将所有上下文数据作为方法参数传递给它;
2.观察者模式原理
- 抽象被观察者(Subject):把所有观察者对象保存在一个集合里,每个被观察者都可以有任意数量的观察者,抽象被观察者提供一个接口,可以增加和删除观察者对象;
- 具体被观察者(ConcreteSubject):将有关状态存入具体观察者对象,在具体被观察者的内部状态发生改变时,给所有注册过的观察者发送通知;
- 抽象观察者(Observer):是观察者的抽象类,定义了一个更新接口,使得在得到被观察者更改通知时更新自己;
- 具体观察者(ConcreteObserver):实现抽象观察者定义的更新接口,以便在得到被观察者更改通知时更新自身的状态,在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要与具体目标一致;
3.观察者模式的实现
【实例】
实现一个买房摇号的程序,摇号结束,需要通过短信告知用户摇号结果,还需要向MQ中保存用户本次摇号的信息。
【代码】
事件监听
java
/**
* 事件监听接口
**/
public interface EventListener {
void doEvent(LotteryResult result);
}
/**
* 短信发送事件
**/
public class MessageEventListener implements EventListener {
@Override
public void doEvent(LotteryResult result) {
System.out.println("发送短信通知用户ID为: " + result.getuId() +
",您的摇号结果如下: " + result.getMsg());
}
}
/**
* MQ消息发送事件
**/
public class MQEventListener implements EventListener {
@Override
public void doEvent(LotteryResult result) {
System.out.println("记录用户摇号结果(MQ), 用户ID:" + result.getuId() +
",摇号结果:" + result.getMsg());
}
}
事件处理
java
/**
* 事件处理类
**/
public class EventManager {
public enum EventType{
MQ,Message
}
//监听器集合
Map<Enum<EventType>, List<EventListener>> listeners = new HashMap<>();
public EventManager(Enum<EventType>... operations) {
for (Enum<EventType> operation : operations) {
this.listeners.put(operation,new ArrayList<>());
}
}
/**
* 订阅
*/
public void subscribe(Enum<EventType> eventType, EventListener listener){
List<EventListener> users = listeners.get(eventType);
users.add(listener);
}
/**
* 取消订阅
*/
public void unsubscribe(Enum<EventType> eventType,EventListener listener){
List<EventListener> users = listeners.get(eventType);
users.remove(listener);
}
/**
* 通知
*/
public void notify(Enum<EventType> eventType, LotteryResult result){
List<EventListener> users = listeners.get(eventType);
for (EventListener listener : users) {
listener.doEvent(result);
}
}
}
摇号业务处理
java
/**
* 开奖服务接口
**/
public abstract class LotteryService{
private EventManager eventManager;
public LotteryService(){
//设置事件类型
eventManager = new EventManager(EventManager.EventType.MQ, EventManager.EventType.Message);
//订阅
eventManager.subscribe(EventManager.EventType.Message,new MessageEventListener());
eventManager.subscribe(EventManager.EventType.MQ,new MQEventListener());
}
public LotteryResult lotteryAndMsg(String uId){
LotteryResult result = lottery(uId);
//发送通知
eventManager.notify(EventManager.EventType.Message,result);
eventManager.notify(EventManager.EventType.MQ,result);
return result;
}
public abstract LotteryResult lottery(String uId);
}
/**
* 开奖服务
**/
public class LotteryServiceImpl extends LotteryService {
//注入摇号服务
private DrawHouseService houseService = new DrawHouseService();
@Override
public LotteryResult lottery(String uId) {
//摇号
String result = houseService.lots(uId);
return new LotteryResult(uId,result,new Date());
}
}
测试
java
@Test
public void test2(){
LotteryService ls = new LotteryServiceImpl();
LotteryResult result = ls.lotteryAndMsg("1234567887654333");
System.out.println(result);
}
4.JDK 中对观察者模式的支持
JDK中提供了Observable类以及Observer接口,它们构成了JDK对观察者模式的支持;
-
java.util.Observer
接口: 该接口中声明了一个方法,它充当抽象观察者,其中声明了一个update方法.void update(Observable o, Object arg);
-
java.util.Observable
类: 充当观察目标类(被观察类) , 在该类中定义了一个Vector集合来存储观察者对象.下面是它最重要的 3 个方法。- void addObserver(Observer o) 方法:用于将新的观察者对象添加到集合中。
-
void notifyObservers(Object arg) 方法:调用集合中的所有观察者对象的 update方法,通知它们数据发生改变。通常越晚加入集合的观察者越先得到通知。
-
void setChange() 方法:用来设置一个 boolean 类型的内部标志,注明目标对象发生了变化。当它为true时,notifyObservers() 才会通知观察者。
用户可以直接使用Observer接口和Observable类作为观察者模式的抽象层,再自定义具体观察者类和具体观察目标类,使用JDK中提供的这两个类可以更加方便的实现观察者模式.