为整个服务中使用的数据对象设计通用接口
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为整个服务中使用的数据对象设计通用接口相关的知识,希望对你有一定的参考价值。
正在迁移一些遗留代码,我遇到了这个问题。
@Getter
@Setter
public class CollectedData
{
SkillResponse skills;
TrendingResponse storyMatch;
Map<String, String> slotData;
Map<String, String> slotDataSecondSource;
Boolean hasSlots;
Boolean hasSlotsSecondSource;
KnowledgeRequest request;
}
由于我一直在使用java 8并习惯于流,因此我开始将此响应类重组为...
@Getter
@Setter
public class CollectedData
{
List<DataSupplierResponse> dataSupplierResponses;
Metadata metadata;
}
DataSupplierResponse是一个定义的接口,如此...
public interface DataSupplierResponse<T>
{
DataSupplierType getDataSupplierType();
T getSupplierResponse();
}
实施例:
public class DataSupplierResponseImpl implements DataSupplierResponse<TrendingResponse>
{
private TrendingResponse mTrendingResponse;
public DataSupplierResponseImpl(
TrendingResponse trendingResponse)
{
mTrendingResponse = trendingResponse;
}
@Override
public DataSupplierType getDataSupplierType()
{
return DataSupplierType.TRENDING_STORY;
}
@Override
public TrendingResponse getSupplierResponse()
{
return mTrendingResponse;
}
}
目标是根据CollectedData
运行某些谓词。
Optional<DataSupplierResponse> first = data.getDataSupplierResponses().stream()
.filter(res -> res.getDataSupplierType().equals(DataSupplierType.TRENDING_STORY))
.findFirst();
这需要一个演员才能获得正确的对象。它返回Object
TrendingResponse match = first.get().getSupplierResponse();
因此,当我开始重构时,我假设通过创建返回不同数据的通用接口来解决这个可用数据问题。为了使这个代码工作,我将不得不转换getSupplierResponse的返回对象,这违背了使用泛型的目的。为了我自己,我需要让这个Data Carrier对象尽可能干净漂亮。任何想法我应该如何构建这些类,和/或如何使用泛型来解决这个问题。
编辑:我知道StackOverflow社区喜欢实施客观,具体的答案,但还有其他设计问题?
你必须在List
中用泛型来指定CollectedData
。例如:
List<DataSupplierResponse> dataSupplierResponse;
应该是:
List<DataSupplierResponse<YourType>> dataSupplierResponse;
其中YourType
对应于响应的类型。这是因为当使用RawType
(没有实际指定泛型的泛型类)时,该类的所有通用信息都被消除了。这就是它返回Object
s的原因,你必须手动施放它。
除非在其他地方使用,否则我将摆脱enumeration
类型DataSupplierType
,因为classes
TrendingResponse
(和其他人)已经提供歧视标准。
(还要记住,enums
是完整的classes
)
对此的完美响应可以为您的响应实现基本类型,例如:
interface Response {
int getScore(); // implement in subclasses
String getName(); // implement in subclasses
}
class TrendingResponse implements Response {}
class SkillResponse implements Response {}
class OtherResponse implements Response {}
但这不是绝对必要的。
在这一点上只需一个通用的包装器class
就足够了(不需要有一个基础interface
并为每种类型的响应扩展它):
class DataSupplierResponse<T extends Response> {
private T t;
public DataSupplierResponse(final T t) {
this.t = t;
}
public T getSupplierResponse() {
return this.t;
}
}
这将允许您致电:
Optional<DataSupplierResponse<?>> first = data.responses
.stream()
.filter(response -> TrendingResponse.class.isAssignableFrom(response.getClass()))
.findFirst();
first.ifPresent( o -> o.getSupplierResponse().getScore() );
或者干脆
Optional<?> first = data.responses
.stream()
.filter(response -> TrendingResponse.class.isAssignableFrom(response.getClass()))
.map(r -> r::getSupplierResponse)
.findFirst();
即使没有基本接口Response
(仅用于定义响应中的常见行为),您的class DataSupplierResponse<T>
也不需要enumeration
类型。
以上是关于为整个服务中使用的数据对象设计通用接口的主要内容,如果未能解决你的问题,请参考以下文章
Express实战 - 应用案例- realworld-API - 路由设计 - mongoose - 数据验证 - 密码加密 - 登录接口 - 身份认证 - token - 增删改查API(代码片段