栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

文章目录
  • 一、什么是观察者模式
  • 二、为什么要使用观察者模式
  • 三、代码示例
    • 代码示例-01(不使用观察者模式实现的业务逻辑)
    • 代码示例-02(使用观察者模式对[代码示例01]进行优化)
    • 代码示例-03(使用SpringBoot自带的事件机制实现)
  • 四、在源码中的应用
    • 1丶观察者模式在Spring框架中的应用
  • 五丶在实际开发中的应用
  • 六、总结


一、什么是观察者模式

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

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

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

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

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

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

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

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

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

@Service
public class StageServiceImpl {

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

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

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

	}
}
代码示例-02(使用观察者模式对[代码示例01]进行优化)
//分期配置编辑的监听器
public interface IStageConfigEditListener {
    
    void stageConfigEditNotify(StageInfoForm form);
}

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

    
    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 stageConfigEditListeners;

    @Autowired(required = false)
    private List 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 {

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

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

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

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

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

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

四、在源码中的应用 1丶观察者模式在Spring框架中的应用

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

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

	
	void addApplicationListener(ApplicationListener listener);

	
	void addApplicationListenerBean(String listenerBeanName);

	
	void removeApplicationListener(ApplicationListener listener);

	
	void removeApplicationListenerBean(String listenerBeanName);

	
	void removeApplicationListeners(Predicate> predicate);

	
	void removeApplicationListenerBeans(Predicate predicate);

	
	void removeAllListeners();

	
	void multicastEvent(ApplicationEvent event);

	
	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> applicationListeners = new LinkedHashSet<>();
		
		public final Set applicationListenerBeans = new LinkedHashSet<>();
		
		public Collection> getApplicationListeners() {
			List> 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 extends EventListener {

	
	void onApplicationEvent(E event);


	
	static  ApplicationListener> forPayload(Consumer consumer) {
		return event -> consumer.accept(event.getPayload());
	}

}

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

public abstract class ApplicationEvent extends EventObject {

	
	private static final long serialVersionUID = 7099057708183571937L;

	
	private final long timestamp;


	
	public ApplicationEvent(Object source) {
		super(source);
		this.timestamp = System.currentTimeMillis();
	}


	
	public final long getTimestamp() {
		return this.timestamp;
	}
}

ClearCachesApplicationListener为具体的观察者

package org.springframework.boot;
class ClearCachesApplicationListener implements ApplicationListener {

	@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,观察者模式仅限在同一模块的业务中使用

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1020788.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号