跳至主要內容

【设计模式】结构型-④注册器模式

holic-x...大约 6 分钟设计模式设计模式

【设计模式】结构型-④注册器模式

学习核心

  • 注册器模式核心(单例模式的特例化)
    • 概念:在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.由数据源决定要调用的搜索方法
    }
}
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.1.3