设计模式-适配器模式-注册器模式

发布于:2024-12-07 ⋅ 阅读:(57) ⋅ 点赞:(0)

设计模式-适配器模式-注册器模式

适配器模式

如果开发一个搜索中台,需要适配或接入不同的数据源,可能提供的方法参数和平台调用的方法参数不一致,可以使用适配器模式

image-20241129230331103

适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至察觉不到适配器的存在。 例如, 你可以使用一个将所有数据转换为英制单位 (如英尺和英里) 的适配器封装运行于米和千米单位制中的对象。

下面这段代码

postService,userService,imageService分别调用的方法逻辑相同参数不同,可使用接口统一调用

@Component
@Slf4j
public class SearchFacade {

    @Resource
    private PostService postService;

    @Resource
    private UserService userService;

    @Resource
    private ImageService imageService;

    @Resource
    ThreadPoolTaskExecutor threadPoolTaskExecutor;

    public SearchVo searchAll(@RequestBody SearchQueryRequest searchQueryRequest, HttpServletRequest httpServletRequest) {
        SearchVo searchVo = new SearchVo();
        if (searchQueryRequest == null) {
            return searchVo;
        }
        String searchText = searchQueryRequest.getSearchText();
        String searchType = searchQueryRequest.getSearchType();
        if (StringUtils.isBlank(searchType)) {
            CompletableFuture<Page<PostVO>> postTask = CompletableFuture.supplyAsync(() -> {
                PostQueryRequest postQueryRequest = new PostQueryRequest();
                postQueryRequest.setSearchText(searchText);
                Page<PostVO> postVOPage = postService.listPostVoPage(postQueryRequest, httpServletRequest);
                return postVOPage;
            }, threadPoolTaskExecutor);

            CompletableFuture<Page<UserVO>> userTask = CompletableFuture.supplyAsync(() -> {
                UserQueryRequest userQueryRequest = new UserQueryRequest();
                userQueryRequest.setUserName(searchText);
                Page<UserVO> userVOPage = userService.listUserVoPage(userQueryRequest);
                return userVOPage;
            }, threadPoolTaskExecutor);

            CompletableFuture<Page<Image>> imageTask = CompletableFuture.supplyAsync(() -> {
                ImageQueryRequest imageQueryRequest = new ImageQueryRequest();
                imageQueryRequest.setSearchText(searchText);
                Page<Image> imagePage = imageService.getImageByPage(imageQueryRequest);
                return imagePage;
            }, threadPoolTaskExecutor);

            CompletableFuture.allOf(postTask, userTask, imageTask);

            try {
                Page<PostVO> postVOPage = postTask.get();
                searchVo.setPostList(postVOPage.getRecords());
                Page<UserVO> userVOPage = userTask.get();
                searchVo.setUserList(userVOPage.getRecords());
                Page<Image> imagePage = imageTask.get();
                searchVo.setImageList(imagePage.getRecords());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        } else {
            SearchTypeEnum searchTypeEnum = SearchTypeEnum.getEnumByValue(searchType);
            switch (searchTypeEnum) {
                case POST:
                    PostQueryRequest postQueryRequest = new PostQueryRequest();
                    postQueryRequest.setSearchText(searchText);
                    Page<PostVO> postVOPage = postService.listPostVoPage(postQueryRequest, httpServletRequest);
                    searchVo.setPostList(postVOPage.getRecords());
                    break;
                case USER:
                    UserQueryRequest userQueryRequest = new UserQueryRequest();
                    userQueryRequest.setUserName(searchText);
                    Page<UserVO> userVOPage = userService.listUserVoPage(userQueryRequest);
                    searchVo.setUserList(userVOPage.getRecords());
                    break;
                case IMAGE:
                    ImageQueryRequest imageQueryRequest = new ImageQueryRequest();
                    imageQueryRequest.setSearchText(searchText);
                    Page<Image> imagePage = imageService.getImageByPage(imageQueryRequest);
                    searchVo.setImageList(imagePage.getRecords());
                    break;
                default:
                    break;
            }
        }
        return searchVo;
    }
}

下面实现一个简单的适配器

新建一个数据源接口

/**
 * @author tuaofei
 * @description 查询数据源
 * @date 2024/11/29
 */
public interface SearchDataSource<T> {

    /**
     * 通用查询接口
     * @param searchText
     * @param current
     * @param pageSize
     * @return
     */
    Page<T> doSearch(String searchText, int current, int pageSize);
}

postService.listPostVoPage(postQueryRequest, httpServletRequest)

新增PostDataSource数据源

@Service
@Slf4j
public class PostDataSource implements SearchDataSource<PostVO> {

    @Resource
    private PostService postService;

    @Override
    public Page<PostVO> doSearch(String searchText, int current, int pageSize) {
        PostQueryRequest postQueryRequest = new PostQueryRequest();
        postQueryRequest.setSearchText(searchText);
        postQueryRequest.setCurrent(current);
        postQueryRequest.setPageSize(pageSize);
        //HttpServletRequest 这里没法获取,考虑改造接口或改造方法,根据具体情况判断
        Page<PostVO> postVOPage = postService.listPostVoPage(postQueryRequest, null);
        return postVOPage;
    }
}

新增UserDataSource 数据源

userService.listUserVoPage(userQueryRequest)

@Service
@Slf4j
public class UserDataSource implements SearchDataSource<UserVO> {

    @Resource
    private UserService userService;

    @Override
    public Page<UserVO> doSearch(String searchText, int current, int pageSize) {
        UserQueryRequest userQueryRequest = new UserQueryRequest();
        userQueryRequest.setUserName(searchText);
        Page<UserVO> userVOPage = userService.listUserVoPage(userQueryRequest);
        return userVOPage;
    }
}

新增ImageDataSource 数据源

imageService.getImageByPage(imageQueryRequest)

@Service
public class ImageDataSource implements SearchDataSource<Image> {

    @Resource
    private ImageService imageService;

    @Override
    public Page<Image> doSearch(String searchText, int current, int pageSize) {
        ImageQueryRequest imageQueryRequest = new ImageQueryRequest();
        imageQueryRequest.setSearchText(searchText);
        imageQueryRequest.setCurrent(current);
        imageQueryRequest.setPageSize(pageSize);
        Page<Image> imageByPage = imageService.getImageByPage(imageQueryRequest);
        return imageByPage;
    }
}

修改SearchFacade里面调用service的逻辑,这样就可以统一调用相同参数的方法,转换逻辑交给具体的数据源

@Component
@Slf4j
public class SearchFacade {

    @Resource
    private ImageDataSource imageDataSource;

    @Resource
    private PostDataSource postDataSource;

    @Resource
    private UserDataSource userDataSource;

    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    public SearchVo searchAll(@RequestBody SearchQueryRequest searchQueryRequest, HttpServletRequest httpServletRequest) {
        SearchVo searchVo = new SearchVo();
        if (searchQueryRequest == null) {
            return searchVo;
        }
        String searchText = searchQueryRequest.getSearchText();
        String searchType = searchQueryRequest.getSearchType();
        int current = searchQueryRequest.getCurrent();
        int pageSize = searchQueryRequest.getPageSize();
        if (StringUtils.isBlank(searchType)) {
            CompletableFuture<Page<PostVO>> postTask = CompletableFuture.supplyAsync(() -> {
                Page<PostVO> postVOPage = postDataSource.doSearch(searchText, current, pageSize);
                return postVOPage;
            }, threadPoolTaskExecutor);

            CompletableFuture<Page<UserVO>> userTask = CompletableFuture.supplyAsync(() -> {
                Page<UserVO> userVOPage = userDataSource.doSearch(searchText, current, pageSize);
                return userVOPage;
            }, threadPoolTaskExecutor);

            CompletableFuture<Page<Image>> imageTask = CompletableFuture.supplyAsync(() -> {
                Page<Image> imagePage = imageDataSource.doSearch(searchText, current, pageSize);
                return imagePage;
            }, threadPoolTaskExecutor);

            CompletableFuture.allOf(postTask, userTask, imageTask);

            try {
                Page<PostVO> postVOPage = postTask.get();
                searchVo.setPostList(postVOPage.getRecords());
                Page<UserVO> userVOPage = userTask.get();
                searchVo.setUserList(userVOPage.getRecords());
                Page<Image> imagePage = imageTask.get();
                searchVo.setImageList(imagePage.getRecords());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        } else {
            SearchTypeEnum searchTypeEnum = SearchTypeEnum.getEnumByValue(searchType);
            switch (searchTypeEnum) {
                case POST:
                    Page<PostVO> postVOPage = postDataSource.doSearch(searchText, current, pageSize);
                    ;
                    searchVo.setPostList(postVOPage.getRecords());
                    break;
                case USER:
                    Page<UserVO> userVOPage = userDataSource.doSearch(searchText, current, pageSize);
                    searchVo.setUserList(userVOPage.getRecords());
                    break;
                case IMAGE:
                    Page<Image> imagePage = imageDataSource.doSearch(searchText, current, pageSize);
                    searchVo.setImageList(imagePage.getRecords());
                    break;
                default:
                    break;
            }
        }
        return searchVo;
    }
}

注册器模式

经过上面的修改,我们发现所有的调用查询方法参数都相同,而且都是通过调用实现了SearchDataSource接口的实现类来调用

我们可以简化下面的switch

SearchTypeEnum searchTypeEnum = SearchTypeEnum.getEnumByValue(searchType);
            switch (searchTypeEnum) {
                case POST:
                    Page<PostVO> postVOPage = postDataSource.doSearch(searchText, current, pageSize);
                    ;
                    searchVo.setPostList(postVOPage.getRecords());
                    break;
                case USER:
                    Page<UserVO> userVOPage = userDataSource.doSearch(searchText, current, pageSize);
                    searchVo.setUserList(userVOPage.getRecords());
                    break;
                case IMAGE:
                    Page<Image> imagePage = imageDataSource.doSearch(searchText, current, pageSize);
                    searchVo.setImageList(imagePage.getRecords());
                    break;
                default:
                    break;
            }

需要一个Map<String,SearchDataSource>来注册这些数据源,通过类型来获取对应的数据源,再调用查询方法

@Component
public class DataSourceRegistry {

    @Resource
    private ImageDataSource imageDataSource;

    @Resource
    private PostDataSource postDataSource;

    @Resource
    private UserDataSource userDataSource;

    private Map<String, SearchDataSource<T>> dataSourceMap;

    /**
     * 在依赖注入完成后,执行
     */
    @PostConstruct
    public void doInit() {
        dataSourceMap = new HashMap() {{
            put(SearchTypeEnum.POST.getValue(), postDataSource);
            put(SearchTypeEnum.USER.getValue(), userDataSource);
            put(SearchTypeEnum.IMAGE.getValue(), imageDataSource);
        }};
    }

    public SearchDataSource getDataSourceByType(String searchType) {
        if (dataSourceMap == null) {
            return null;
        }
        return dataSourceMap.get(searchType);
    }
}

在SearchFacade使用

@Component
@Slf4j
public class SearchFacade {

    @Resource
    private DataSourceRegistry dataSourceRegistry;

    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    public SearchVo searchAll(@RequestBody SearchQueryRequest searchQueryRequest, HttpServletRequest httpServletRequest) {
        SearchVo searchVo = new SearchVo();
        if (searchQueryRequest == null) {
            return searchVo;
        }
        String searchText = searchQueryRequest.getSearchText();
        String searchType = searchQueryRequest.getSearchType();
        int current = searchQueryRequest.getCurrent();
        int pageSize = searchQueryRequest.getPageSize();
        if (StringUtils.isBlank(searchType)) {
            CompletableFuture<Page<PostVO>> postTask = CompletableFuture.supplyAsync(() -> {
                SearchDataSource postDataSource = dataSourceRegistry.getDataSourceByType(SearchTypeEnum.POST.getValue());
                Page<PostVO> postVOPage = postDataSource.doSearch(searchText, current, pageSize);
                return postVOPage;
            }, threadPoolTaskExecutor);

            CompletableFuture<Page<UserVO>> userTask = CompletableFuture.supplyAsync(() -> {
                SearchDataSource userDataSource = dataSourceRegistry.getDataSourceByType(SearchTypeEnum.USER.getValue());
                Page<UserVO> userVOPage = userDataSource.doSearch(searchText, current, pageSize);
                return userVOPage;
            }, threadPoolTaskExecutor);

            CompletableFuture<Page<Image>> imageTask = CompletableFuture.supplyAsync(() -> {
                SearchDataSource imageDataSource = dataSourceRegistry.getDataSourceByType(SearchTypeEnum.IMAGE.getValue());
                Page<Image> imagePage = imageDataSource.doSearch(searchText, current, pageSize);
                return imagePage;
            }, threadPoolTaskExecutor);

            CompletableFuture.allOf(postTask, userTask, imageTask);

            try {
                Page<PostVO> postVOPage = postTask.get();
                searchVo.setPostList(postVOPage.getRecords());
                Page<UserVO> userVOPage = userTask.get();
                searchVo.setUserList(userVOPage.getRecords());
                Page<Image> imagePage = imageTask.get();
                searchVo.setImageList(imagePage.getRecords());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        } else {
            SearchDataSource<?> dataSource = dataSourceRegistry.getDataSourceByType(searchType);
            //可以使用公共的返回对象,类型使用泛型
            Page<?> page = dataSource.doSearch(searchText, current, pageSize);
            List<?> records = page.getRecords();
            searchVo.setDataList(records);
        }
        return searchVo;
    }
}

在SearchVo新建公共返回对象

@Data
public class SearchVo implements Serializable {

    private List<PostVO> postList;
    private List<Image> imageList;
    private List<UserVO> userList;

    /**
     * 公共返回对象
     */
    private List<?> dataList;
}