前面我已经学写了创建型的四种 单例式 工厂式 建造者模式,原型模式这是为了解决对象的创建问题,
结构型为了解决类和对象的组合和组装问题有代理模式,桥接模式,装饰模式,适配器模式,门面模式,组合模式,享元模式
现在学习行为型设计模式,为了解决类和对象支间的交互问题
这是第一个行为型设计模式,我们一共要学习11个,
观察者模式
也被叫做发布订阅模式,其含义为在对象之间定义一个一对多的依赖,当这个对象的状态发生改变的时候,会通知所有依赖的对象,在实际的项目开发中,观察者和被观察者的称呼很灵活,比如Subject-Observer等,不过,不管怎么说,只要场景符合就行
下面给出了一种最简单的实现方式
public interface Subject {
void registerObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers(Message message); } public interface Observer { void update(Message message); } public class ConcreteSubject implements Subject { private List<Observer> observers = new ArrayList<Observer>(); @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers(Message message) { for (Observer observer : observers) { observer.update(message); } } } public class ConcreteObserverOne implements Observer { @Override public void update(Message message) { //TODO: 获取消息通知,执行自己的逻辑… System.out.println(“ConcreteObserverOne is notified.”); } } public class ConcreteObserverTwo implements Observer { @Override public void update(Message message) { //TODO: 获取消息通知,执行自己的逻辑… System.out.println(“ConcreteObserverTwo is notified.”); } } public class Demo { public static void main(String[] args) { ConcreteSubject subject = new ConcreteSubject(); subject.registerObserver(new ConcreteObserverOne()); subject.registerObserver(new ConcreteObserverTwo()); subject.notifyObservers(new Message()); } } |
那么,什么时候会用上这种设计模式呢?
比如,我们一个P2P的理财系统,对于用户注册的时候,会发送体验金
public class UserController {
private UserService userService; // 依赖注入 private PromotionService promotionService; // 依赖注入 public Long register(String telephone, String password) { //省略输入参数的校验代码 //省略userService.register()异常的try-catch代码 long userId = userService.register(telephone, password); promotionService.issueNewUserExperienceCash(userId); return userId; } } |
这个接口做了两件事,一件是注册,一件是发放体验金
如果为了应对未来的接口需求变化,我们可以改为
观察者模式,在注册成功的时候,其他的系统在用户系统中的注册都会得到提示,从而执行对应的任务
public interface RegObserver {
void handleRegSuccess(long userId); } public class RegPromotionObserver implements RegObserver { private PromotionService promotionService; // 依赖注入 @Override public void handleRegSuccess(long userId) { promotionService.issueNewUserExperienceCash(userId); } } public class RegNotificationObserver implements RegObserver { private NotificationService notificationService; @Override public void handleRegSuccess(long userId) { notificationService.sendInboxMessage(userId, “Welcome…”); } } public class UserController { private UserService userService; // 依赖注入 private List<RegObserver> regObservers = new ArrayList<>(); // 一次性设置好,之后也不可能动态的修改 public void setRegObservers(List<RegObserver> observers) { regObservers.addAll(observers); } public Long register(String telephone, String password) { //省略输入参数的校验代码 //省略userService.register()异常的try-catch代码 long userId = userService.register(telephone, password); for (RegObserver observer : regObservers) { observer.handleRegSuccess(userId); } return userId; } } |
上面就是在注册成功了,有两个要执行的注册的观察者被触发了,这样的接口逻辑,也符合开闭原则
其实,大部分设计模式所在做的工作,就是在解耦,创建型模式,就是讲创建一个对象和使用对象解耦,结构型,则是将不同功能之间解耦,行为型模式就是讲不同的行为解耦
然后说回观察者模式
小到代码层面的解耦,大到架构层面的系统解耦,都可以应用观察者模式,比如邮件订阅
对于不同的应用场景下,可以有不同的实现方式,有同步阻塞的,异步非阻塞的异步阻塞的
向上面的场景,如果注册接口调用很频繁,那么可以改为异步非阻塞的实现方式,这样当注册函数执行完成了,就可以直接返回了,剩下的订阅者的执行,就是由一个新的异步线程执行了
甚至说,使用内部的EventsBus
刚刚两个场景,不管是异步还是同步,都是进程内实现的,如果需要系统之间来交互,除了使用一般的RPC接口,还可以使用消息队列来实现
从而做到解耦,这样观察者和被观察者绝对解耦,并不会感知彼此