使用注册模式 + 门面模式优化聚合搜索引擎代码

907 阅读2分钟

使用注册模式 + 门面模式优化聚合搜索引擎代码

什么是聚合搜索

最近在做一个搜索引擎的小demo

image-20230413133108978

此类系统有很多案例,比如bing的搜索,你在搜索框中搜你想要搜索的文字,根据下方的tab栏进行切换,可以搜索到不同种类的东西。

再比如说b站的搜索引擎

image-20230413133317636

会根据搜索出来的词,提供不同种类的搜索结果。

设计分析

其实,对于此类搜索引擎,每一个标签的切换,都意味着在不同的数据源中进行搜索。

如果每一个数据源的调用都是一个新的接口的话,前端同学会遇到以下两个问题:

  • 对于前端来说,由于在页面初始化的时候,一次性只能调用6次请求。等这6次请求全部调用完,才能进行接下来的6个请求的调用。对于页面的渲染不利。
  • 并且,如果不同的数据源的传入参数,路径都不同,前端代码冗杂,不利于维护

所以,作为一个合格的后端,我们要做的应该是减少前端同学对于请求内容的整理,尽量做到一个接口解决完所有问题。

门面模式

门面模式就是为了这个场景而生的。

什么是门面模式?

门面模式要求子系统的外部和内部的通信,必须要通过一个统一的门面来进行。

就好像是一个商品售卖员,你要香烟,它会给你,你要水,它也会给你一样。你要做的只是向她去提出你想要的东西。

门面模式相当于给你提供了一个高层次的接口,使得子系统易于调用。

对于前端同学来说,无疑是大大减轻了他们的负担。从代码层面上来说,规范了请求路径,传参。易于调用。

请求路径:/api/search/page/vo
{
    type:"图片 || 文章 || 热榜 ||"
    searchText:"",
    current:
    pageSize
}

后端实现门面模式

1.设计门面类

设计SearchFacade类。(facade 就是门面的意思)

这个类里面写searchAll的方法。统一传入参数,实现搜索到的数据返回。

@Component
@Slf4j
public class SearchFacade {
​
​
​
    @PostMapping
    public SearchVO searchAll(@RequestBody SearchQueryRequest searchQueryRequest) {
       
    }
​
}

2.设置数据源接口

public interface DataSource<T> {
​
    Page<T> search(String searchText, long current, long pageSize);
​
}
​

3.实现数据源接口

@Component
public class JueArticleDatasource implements DataSource<JueArticle>{
​
    @Resource
    private JueArticleService jueArticleService;
​
​
    @Override
    public Page<JueArticle> search(String searchText, long current, long pageSize) {
        return jueArticleService.searchArticle(searchText,current,pageSize);
    }
}
​
@Component
public class PictureDataSource implements DataSource<Picture>{
​
    @Resource
    private PictureService pictureService;
​
​
    @Override
    public Page<Picture> search(String searchText, long current, long pageSize) {
        return pictureService.searchPicture(searchText,current,pageSize);
    }
}
​
@Component
public class ArticleDataSource implements DataSource<PostVO>{
​
    @Resource
    private PostService postService;
​
​
    @Override
    public Page<PostVO> search(String searchText, long current, long pageSize) {
        PostQueryRequest postQueryRequest = new PostQueryRequest();
        postQueryRequest.setSearchText(searchText);
        Page<Post> postPage = postService.page(new Page<>(current, pageSize),
                postService.getQueryWrapper(postQueryRequest));
        return postService.getPostVOPage(postPage, null);
    }
}

注意,这里由于service里面的方法传的值不一样,我们就可以在datasource的实现类中,对参数进行适配,这也是适配器模式的思想体现。

4.利用注册模式注册数据源

@Component
public class DataSourceRegistry {
​
    @Resource
    private ArticleDataSource articleDataSource;
​
    @Resource
    private PictureDataSource pictureDataSource;
​
    @Resource
    private JueArticleDatasource jueArticleDatasource;
​
​
    private Map<DataSourceTypeEnum,DataSource> dataSourceMap;
​
​
    @PostConstruct
    public void initDataSourceMap(){
        dataSourceMap = new HashMap<>();
        dataSourceMap.put(DataSourceTypeEnum.Article,articleDataSource);
        dataSourceMap.put(DataSourceTypeEnum.JueArticle,jueArticleDatasource);
        dataSourceMap.put(DataSourceTypeEnum.Picture,pictureDataSource);
    }
    /**
     * 这里也有策略模式的思想体现,根据type找到相应的数据源服务
     **/
    public DataSource getDataSourceByType(String type){
        DataSourceTypeEnum typeEnum = DataSourceTypeEnum.getEnumByValue(type);
        return dataSourceMap.get(typeEnum);
    }
}
​

5.在search门面中选择相应的数据源进行查询。

@Component
@Slf4j
public class SearchFacade {
​
​
    @Resource
    private DataSourceRegistry dataSourceRegistry;
​
​
    @PostMapping
    public SearchVO searchAll(@RequestBody SearchQueryRequest searchQueryRequest) {
        SearchVO searchVO = new SearchVO();
        String searchText = searchQueryRequest.getSearchText();
        long current = searchQueryRequest.getCurrent();
        long pageSize = searchQueryRequest.getPageSize();
        String type = searchQueryRequest.getType();
​
        DataSource<?> dataSource = dataSourceRegistry.getDataSourceByType(type);
        Page search = dataSource.search(searchText, current, pageSize);
        searchVO.setDataList(search.getRecords());
        return searchVO;
    }
​
}