为整个服务中使用的数据对象设计通用接口

问题描述 投票:2回答:2

正在迁移一些遗留代码,我遇到了这个问题。

@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社区喜欢实施客观,具体的答案,但还有其他设计问题?

java generics interface architecture java-8
2个回答
2
投票

你必须在List中用泛型来指定CollectedData。例如:

List<DataSupplierResponse> dataSupplierResponse;

应该是:

List<DataSupplierResponse<YourType>> dataSupplierResponse;

其中YourType对应于响应的类型。这是因为当使用RawType(没有实际指定泛型的泛型类)时,该类的所有通用信息都被消除了。这就是它返回Objects的原因,你必须手动施放它。


1
投票

除非在其他地方使用,否则我将摆脱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类型。

© www.soinside.com 2019 - 2024. All rights reserved.