JAVA设计模式-行为型-观察者模式


一、什么是观察者模式

官方定义:
定义对象之间的一对多依赖,让多个观察者对象同时监听某一主题对象,当主题对象发生变化时,它的所有依赖着都会受到通知并更新

个人理解:
观察者模式就是在一段逻辑中,除了该方法的核心逻辑之外还有很多非核心但是存在依赖的业务逻辑,导致代码过多且复杂,不利于后期维护,将可以使用观察者模式进行解耦.

一句话说明就是使用观察者模式将核心逻辑与非核心逻辑进行解耦.

二、为什么要使用观察者模式

请先看 [代码示例-01]
通过案例可以看出来,这就是平常业务中常有的逻辑,在大部分时候代码也就是这么写的,这种写法在关联的模块较少的情况下是没啥大问题的,但是架不住产品的迭代,例如这个分期配置业务,一开始只有3个关联模块,后面基本一个版本加一个关联模块,时间长了就会导致这个方法特别臃肿,这种情况就是非核心逻辑过多的问题.

现在通过 [代码示例-02] 使用观察者模式进行优化
通过案例可以看出来,使用观察者模式从代码层面上将核心业务(编辑分期/删除分期)跟非核心业务(分期关联模块)进行了解耦.

这就是使用观察者模式的好处,后期新增分期的关联模块时,只需要在关联模块中实现监听类做具体业务就好了,分期的核心代码则不需要任何的改动(符合开闭原则)

三、代码示例

代码示例-01(不使用观察者模式实现的业务逻辑)

需求:
编辑分期时,需要将跟分期相关联的业务表的数据先清空,然后重新保存
目前我们项目中跟分期关联的模块大约有8个左右

@Service
public class StageServiceImpl {

   public void editStage(StageInfoForm form) {
	//编辑分期的代码....

	//清空分期流程数据,重新保存...
	updateStageProcess();
	
	//清空分期白名单数据,重新保存
	updateStageWhiteList();

	//后面的省略(明白意思就好)............

	}
}

代码示例-02(使用观察者模式对[代码示例01]进行优化)

//分期配置编辑的监听器
public interface IStageConfigEditListener {
    /**
     * 分期配置编辑通知
     *
     * @param form
     */
    void stageConfigEditNotify(StageInfoForm form);
}

//删除分期的监听器
public interface StageRemoveListener {

    /**
     * 分期删除通知
     * @param form
     */
    void stageRemoveNotify(StageInfoForm form);
}

//关联模块-分期流程Service 
@Service
@Slf4j
public class StageProcessServiceImpl implements IStageConfigEditListener, StageRemoveListener {

    @Override
    public void stageConfigEditNotify(StageInfoForm form) {
        log.info("配置分期流程....");
    }

    @Override
    public void stageRemoveNotify(StageInfoForm form) {
        log.info("删除分期流程....");
    }
}

//关联模块-分期白名单Service 
@Slf4j
@Service
public class StageWhiteListServiceImpl implements IStageConfigEditListener, StageRemoveListener {

    @Override
    public void stageConfigEditNotify(StageInfoForm form) {
        log.info("配置分期白名单....");
    }

    @Override
    public void stageRemoveNotify(StageInfoForm form) {
        log.info("删除分期白名单....");
    }
}

//分期事件管理器 统一管理分期相关的事件业务
@Component
public class StageEventManage {

    @Autowired(required = false)
    private List<IStageConfigEditListener> stageConfigEditListeners;

    @Autowired(required = false)
    private List<StageRemoveListener> stageRemoveListeners;

	//发布分期配置编辑事件
    public void pushStageConfigEditEvent(StageInfoForm form) {
        if (CollUtil.isNotEmpty(stageConfigEditListeners)) {
            stageConfigEditListeners.forEach(item -> item.stageConfigEditNotify(form));
        }
    }
   
    //发布删除分期事件
    public void pushStageRemoveEvent(StageInfoForm form) {
        if (CollUtil.isNotEmpty(stageRemoveListeners)) {
            stageRemoveListeners.forEach(item -> item.stageRemoveNotify(form));
        }
    }
}

//分期模块-Service
@Service
public class StageServiceImpl {
 	
 	//注入分期事件管理器
    @Autowired
    private StageEventManage stageEventManage;


    public void editStage(StageInfoForm form) {

        //编辑分期信息代码...

        //发布编辑事件
        stageEventManage.pushStageConfigEditEvent(form);

    }

    public void removeStage(StageInfoForm form) {
        //删除分期代码...

        //发布删除事件
        stageEventManage.pushStageRemoveEvent(form);
    }
}

//请求表单类
@Data
public class StageInfoForm {
    
}

代码示例-03(使用SpringBoot自带的事件机制实现)

//定义分期配置编辑事件类 因为考虑到后期的扩展,所以使用事件类去包裹业务相关参数
@Data
public class StageConfigEditEvent {
    private StageInfoForm stageInfoForm;
}

//定义分期删除事件类
@Data
public class StageRemoveEvent {
    private StageInfoForm stageInfoForm;
}

//分期事件管理器
@Component
public class StageEventManage {
	
	//重点,需要使用它去发布事件
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;
    
    public void springBootPushStageConfigEditEvent(StageConfigEditEvent event) {
        applicationEventPublisher.publishEvent(event);
    }

    public void springBootPushStageRemoveEvent(StageRemoveEvent event) {
        applicationEventPublisher.publishEvent(event);
    }
}

//分期事件监听类
@Component
@Slf4j
public class StageEventListener {

    /**
     * 分期配置编辑事件监听
     *
     * @param event
     */
    @EventListener(StageConfigEditEvent.class)
    public void stageConfigEdit(StageConfigEditEvent event) {
        log.info("监听到了分期配置编辑事件...");
        
		//清空分期流程数据,重新保存...
		updateStageProcess();
	
		//清空分期白名单数据,重新保存
		updateStageWhiteList();

		//.........
    }

    /**
     * 分期删除事件监听
     *
     * @param event
     */
    @EventListener(StageRemoveEvent.class)
    public void stageRemove(StageRemoveEvent event) {
        log.info("监听到了分期删除事件...");
        
		//删除分期流程数据
		
		//删除分期白名单数据

		//.........
    }
}

通过上诉案例可以看出,使用SpringBoot的事件机制也是可以完成代码的解耦,但是在关联模块太多的情况下不是特别适合使用,从案例中可以看出后期新增关联模块之后需要修改对应监听类的代码(违反了开闭原则),但是在有些情况下直接使用SpringBoot机制会比较方便.

点击跳转查看SpringBoot的事件机制

四、在源码中的应用

1丶观察者模式在Spring框架中的应用

ApplicationEventMulticaster类为观察者模式的顶层接口类

package org.springframework.context.event;
public interface ApplicationEventMulticaster {

	/**
	 * Add a listener to be notified of all events.
	 * @param listener the listener to add
	 * @see #removeApplicationListener(ApplicationListener)
	 * @see #removeApplicationListeners(Predicate)
	 */
	void addApplicationListener(ApplicationListener<?> listener);

	/**
	 * Add a listener bean to be notified of all events.
	 * @param listenerBeanName the name of the listener bean to add
	 * @see #removeApplicationListenerBean(String)
	 * @see #removeApplicationListenerBeans(Predicate)
	 */
	void addApplicationListenerBean(String listenerBeanName);

	/**
	 * Remove a listener from the notification list.
	 * @param listener the listener to remove
	 * @see #addApplicationListener(ApplicationListener)
	 * @see #removeApplicationListeners(Predicate)
	 */
	void removeApplicationListener(ApplicationListener<?> listener);

	/**
	 * Remove a listener bean from the notification list.
	 * @param listenerBeanName the name of the listener bean to remove
	 * @see #addApplicationListenerBean(String)
	 * @see #removeApplicationListenerBeans(Predicate)
	 */
	void removeApplicationListenerBean(String listenerBeanName);

	/**
	 * Remove all matching listeners from the set of registered
	 * {@code ApplicationListener} instances (which includes adapter classes
	 * such as {@link ApplicationListenerMethodAdapter}, e.g. for annotated
	 * {@link EventListener} methods).
	 * <p>Note: This just applies to instance registrations, not to listeners
	 * registered by bean name.
	 * @param predicate the predicate to identify listener instances to remove,
	 * e.g. checking {@link SmartApplicationListener#getListenerId()}
	 * @since 5.3.5
	 * @see #addApplicationListener(ApplicationListener)
	 * @see #removeApplicationListener(ApplicationListener)
	 */
	void removeApplicationListeners(Predicate<ApplicationListener<?>> predicate);

	/**
	 * Remove all matching listener beans from the set of registered
	 * listener bean names (referring to bean classes which in turn
	 * implement the {@link ApplicationListener} interface directly).
	 * <p>Note: This just applies to bean name registrations, not to
	 * programmatically registered {@code ApplicationListener} instances.
	 * @param predicate the predicate to identify listener bean names to remove
	 * @since 5.3.5
	 * @see #addApplicationListenerBean(String)
	 * @see #removeApplicationListenerBean(String)
	 */
	void removeApplicationListenerBeans(Predicate<String> predicate);

	/**
	 * Remove all listeners registered with this multicaster.
	 * <p>After a remove call, the multicaster will perform no action
	 * on event notification until new listeners are registered.
	 * @see #removeApplicationListeners(Predicate)
	 */
	void removeAllListeners();

	/**
	 * Multicast the given application event to appropriate listeners.
	 * <p>Consider using {@link #multicastEvent(ApplicationEvent, ResolvableType)}
	 * if possible as it provides better support for generics-based events.
	 * @param event the event to multicast
	 */
	void multicastEvent(ApplicationEvent event);

	/**
	 * Multicast the given application event to appropriate listeners.
	 * <p>If the {@code eventType} is {@code null}, a default type is built
	 * based on the {@code event} instance.
	 * @param event the event to multicast
	 * @param eventType the type of event (can be {@code null})
	 * @since 4.2
	 */
	void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}

AbstractApplicationEventMulticaster
SimpleApplicationEventMulticaster
这俩个类为[ApplicationEventMulticaster]的具体实现类
这里只列举 addApplicationListener()方法跟 multicastEvent()方法,更多的请自行去查看源码

package org.springframework.context.event;
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
	
	private final DefaultListenerRetriever defaultRetriever = new DefaultListenerRetriever();

	//添加监听者
	@Override
	public void addApplicationListener(ApplicationListener<?> listener) {
		synchronized (this.defaultRetriever) {
			Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
			if (singletonTarget instanceof ApplicationListener) {
				this.defaultRetriever.applicationListeners.remove(singletonTarget);
			}
			//添加listener至集合
			this.defaultRetriever.applicationListeners.add(listener);
			this.retrieverCache.clear();
		}
	}

	
	//内部类,保存listener至Set集合
	private class DefaultListenerRetriever {
		public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
		
		public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
		
		public Collection<ApplicationListener<?>> getApplicationListeners() {
			List<ApplicationListener<?>> allListeners = new ArrayList<>(
					this.applicationListeners.size() + this.applicationListenerBeans.size());
			allListeners.addAll(this.applicationListeners);
			if (!this.applicationListenerBeans.isEmpty()) {
				BeanFactory beanFactory = getBeanFactory();
				for (String listenerBeanName : this.applicationListenerBeans) {
					try {
						ApplicationListener<?> listener =
								beanFactory.getBean(listenerBeanName, ApplicationListener.class);
						if (!allListeners.contains(listener)) {
							allListeners.add(listener);
						}
					}
					catch (NoSuchBeanDefinitionException ex) {
					}
				}
			}
			AnnotationAwareOrderComparator.sort(allListeners);
			return allListeners;
		}
	}
}
package org.springframework.context.event;
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
	@Nullable
	private Executor taskExecutor;

	//执行通知方法
	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		Executor executor = getTaskExecutor();
		
		//这里跟上诉的案例一样,循环ApplicationListener接口的实现类,去执行通知方法
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

	protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			doInvokeListener(listener, event);
		}
	}

	@SuppressWarnings({"rawtypes", "unchecked"})
	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			//这里调用ApplicationListener实现类的onApplicationEvent()方法
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
					(event instanceof PayloadApplicationEvent &&
							matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
				Log loggerToUse = this.lazyLogger;
				if (loggerToUse == null) {
					loggerToUse = LogFactory.getLog(getClass());
					this.lazyLogger = loggerToUse;
				}
				if (loggerToUse.isTraceEnabled()) {
					loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}
}

ApplicationListener为监听者的顶层接口,如果自定义监听类必须实现此接口

package org.springframework.context;
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);


	/**
	 * Create a new {@code ApplicationListener} for the given payload consumer.
	 * @param consumer the event payload consumer
	 * @param <T> the type of the event payload
	 * @return a corresponding {@code ApplicationListener} instance
	 * @since 5.3
	 * @see PayloadApplicationEvent
	 */
	static <T> ApplicationListener<PayloadApplicationEvent<T>> forPayload(Consumer<T> consumer) {
		return event -> consumer.accept(event.getPayload());
	}

}

ApplicationEvent为事件抽象类,如果自定义事件需要继承此抽象类

public abstract class ApplicationEvent extends EventObject {

	/** use serialVersionUID from Spring 1.2 for interoperability. */
	private static final long serialVersionUID = 7099057708183571937L;

	/** System time when the event happened. */
	private final long timestamp;


	/**
	 * Create a new {@code ApplicationEvent}.
	 * @param source the object on which the event initially occurred or with
	 * which the event is associated (never {@code null})
	 */
	public ApplicationEvent(Object source) {
		super(source);
		this.timestamp = System.currentTimeMillis();
	}


	/**
	 * Return the system time in milliseconds when the event occurred.
	 */
	public final long getTimestamp() {
		return this.timestamp;
	}
}

ClearCachesApplicationListener为具体的观察者

package org.springframework.boot;
class ClearCachesApplicationListener implements ApplicationListener<ContextRefreshedEvent> {

	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		ReflectionUtils.clearCache();
		clearClassLoaderCaches(Thread.currentThread().getContextClassLoader());
	}

	private void clearClassLoaderCaches(ClassLoader classLoader) {
		if (classLoader == null) {
			return;
		}
		try {
			Method clearCacheMethod = classLoader.getClass().getDeclaredMethod("clearCache");
			clearCacheMethod.invoke(classLoader);
		}
		catch (Exception ex) {
			// Ignore
		}
		clearClassLoaderCaches(classLoader.getParent());
	}
}

public class ContextRefreshedEvent extends ApplicationContextEvent {
	public ContextRefreshedEvent(ApplicationContext source) {
		super(source);
	}
}

看完应该对SpringBoot中的事件机制的执行逻辑有相应的了解,想要了解的更多请自行查看源码.

五丶在实际开发中的应用

  • [代码示例-02]

六、总结

可以看出观察者模式主要就是在代码层面上进行解耦
但是现在微服务的主流下,模块之间的通信多半是使用的MQ,观察者模式仅限在同一模块的业务中使用

至此,观察者模式就整理完毕辣~~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值