【设计模式】结构型-④注册器模式
【设计模式】结构型-④注册器模式
注
学习核心
- 注册器模式核心(单例模式的特例化)
- 概念:在APP中全局注册对象供其他对象使用,常用于管理和维护一组单例的全局对象(涉及注册对象、注册器两个角色)
- 组成:注册对象、注册器
- 业务场景案例:在应用程序中全局注册一些对象,便于被其他对象发现和使用,常用于管理和维护一组单例的全局对象
- 【search-platform】数据源注册器:【search-platform】中通过定义不同类型的检索数据源(post、user、picture),动态注册,根据type获取不同数据源(替换传统if...else...、switch 语句)
概念说明
注册器主要涉及两个角色:注册器对象、注册器
- 注册器对象:要进行管理的一类对象角色(基于扩展性可设计为接口和对应实现类)
- 注册器:注册中定义一个集合用于全局维护,提供对象注册入口和根据类型获取对象的入口
/**
* 注册对象
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RegisterObject {
private String name;
private String type;
}
/**
* 注册器
*/
public class Register {
// 定义集合全局管理注册对象
private static Map<String ,RegisterObject> map = new HashMap<String ,RegisterObject>();
// 初始化
static{
map.put("obj1",new RegisterObject("对象1","obj1"));
map.put("obj2",new RegisterObject("对象2","obj2"));
}
// 注册对象
public void register(String type,RegisterObject registerObject){
map.put(type,registerObject);
}
// 根据类型获取对象
public RegisterObject getRegister(String type){
return map.get(type);
}
}
应用场景
1.数据源注册(【search-platform】聚合搜索)
注册器模式的主要目的是在应用程序中全局注册一些对象,便于被其他对象发现和使用,常用于管理和维护一组单例的全局对象
使用注册器模式后,不仅能更方便地集中查找和获取全局对象,还避免了反复初始化的内存和时间开销
具体的实现方式如下:
(1)定义注册器类:将注册器类标识为一个 Bean,并且在类中添加一个 HashMap 属性,用于存放全局对象
(2)对象注册:通过 @PostConstruct 注解,在注册器 Bean 加载时初始化 HashMap 并且向其中插入新创建的数据源对象
(3)对象获取:提供一个根据 key(数据源类型)查找对象的方法,返回获取到的对象
注册器模式:
例如在【search-platform】场景中,需要根据不同的类型执行相应的数据源进行检索,数据源信息可以是文章信息post、用户信息user、图片信息picture,通过引入注册器模式将这组数据源信息进行管理
可以理解为特殊的单例模式,针对多个数据源集合的封装可以在springboot项目启动的时候进行注册(类似定义一个全局的静态Map存储数据源信息),通过Map的key-value方式存储(数据源类型-对应数据源),随后对外提供一个获取Map的方法(或者是将Map定义为全局静态变量),则可通过get方法指定数据源类型获取到对应的数据源,以简化if...else...操作。因为目前系统中提供的数据源是在一开始就确定下来的,而不是像是一些动态数据源封装一样,因此可以可以借助注册器模式对全局数据进行注册,进而对switch语句进行了优化,调整为提前通过一个map或者其他类型存储好后面需要调用的对象。其效果体现在替代了if...else...代码量大幅度减少,可维护可扩展
✨普通实现思路(定义Map、静态初始化)
- 数据源(接口定义、接口实现定义)
/**
* 数据源 接口设计
*/
public interface DataSource {
public void search(String searchParam);
}
public class PostDataSource implements DataSource{
@Override
public void search(String searchParam) {
System.out.println("post search: " + searchParam);
}
}
public class UserDataSource implements DataSource{
@Override
public void search(String searchParam) {
System.out.println("user search: " + searchParam);
}
}
public class VideoDataSource implements DataSource{
@Override
public void search(String searchParam) {
System.out.println("video search : " + searchParam);
}
}
- 数据源注册器
/**
* 数据源注册器:统一管理数据源信息
*/
public class DataSourceRegister {
// 数据源集合
private static HashMap<String, DataSource> dataSources = new HashMap<String, DataSource>();
// 初始化数据源信息
static{
dataSources.put("post", new PostDataSource());
dataSources.put("user", new UserDataSource());
dataSources.put("picture", new PictureDataSource());
}
// 注册数据源信息
public static void register(String type,DataSource dataSource){
dataSources.put(type, dataSource);
}
// 根据类型获取数据源信息
public static DataSource getDataSource(String type){
return dataSources.get(type);
}
}
- demo 测试(注册新数据源、根据类型获取数据源进行处理)
/**
* 引入新数据源信息:Video数据源
*/
public class VideoDataSource implements DataSource{
@Override
public void search(String searchParam) {
System.out.println("video search : " + searchParam);
}
}
/**
* 注册器模式应用:数据源注册
* 场景案例(聚合搜索,不同的搜索来源的数据源注册、或不同类型数据源注册)
* 1.本地数据源(数据库文章,可自行管理博客文章内容或基于爬虫机制进行文章爬取) 查询文章信息
* 2.用户信息数据源 (查询文章信息)
* 3.图片数据源(爬取bing图片信息)
* 等....需根据不同数据源进行检索处理
*/
public class DataSourceDemo {
public static void main(String[] args) {
// 注册新数据源
DataSourceRegister.register("video",new VideoDataSource());
// 根据指定类型数据源进行检索
DataSourceRegister.getDataSource("user").search("hello world");
}
}
✨Springboot 框架下实现思路(配合注解进行处理)
# 1.传统数据源获取
HashMap dataSourceMap = new HashMap();
dataSourceMap.put("xxx",new XXXDataSource());
switch(searchType){
// 根据不同类型获取到不同的数据源然后一一匹配处理
}
# 存在问题,大量重复编码编排,有可能遇到其他方法中也要使用到这些数据源集合,又要重新编写
// 2.注册器模式实现:系统启动的时候就将所有数据源注册好
# 2.1 定义一个数据源注册器,通过@Component、@PostConstruct联合使用进行注册
@Component
public class DataSourceRegistry {
@Resource
private XXXDataSource xxxDataSource;
// 定义数据源集合
private Map<String, DataSource<T>> typeDataSourceMap;
// 初始化数据源(将要初始化的数据源集合加载到Map中)
@PostConstruct
public void doInit() {
typeDataSourceMap = new HashMap() {{
put("xxx", xxxDataSource);
}};
}
// 对外提供根据不同类型获取指定数据源的方法
public DataSource getDataSourceByType(String type) {
if (typeDataSourceMap == null) {
return null;
}
return typeDataSourceMap.get(type);
}
}
# 2.2 根据不同查询参数确定使用数据源
public class Demo {
@Resource
private DataSourceRegistry dataSourceRegistry;
public SearchVO searchAll(String type){
// 1.从数据源注册器中获取到对应的数据源信息(注册模式)
DataSource dataSource = dataSourceRegistry.getDataSourceByType(type);
// 2.由数据源决定要调用的搜索方法
}
}
