设计模式-适配器模式-注册器模式
适配器模式
如果开发一个搜索中台,需要适配或接入不同的数据源,可能提供的方法参数和平台调用的方法参数不一致,可以使用适配器模式
适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至察觉不到适配器的存在。 例如, 你可以使用一个将所有数据转换为英制单位 (如英尺和英里) 的适配器封装运行于米和千米单位制中的对象。
下面这段代码
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;
}