You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Movie/BaseDTO继承结构,如何实现含子类字段的父类对象返回与实体转DTO?

解决方案:子类字段兼容的父类返回与实体转DTO实现

嘿,我来帮你搞定这两个需求!先把咱们的基础DTO类结构梳理清楚(完全贴合你描述的继承和Builder设计),再一步步实现功能。

第一步:先定义完整的DTO类结构

首先按照你的要求实现BaseDTO、Movie和UserMovie类,包括泛型Builder的继承:

// 基础DTO抽象类,包含通用字段和Builder基类
abstract class BaseDTO {
    protected final Long id;

    protected BaseDTO(BaseDTO.Builder<?> builder) {
        this.id = builder.id;
    }

    // 泛型Builder基类,确保链式调用的类型正确性
    abstract static class Builder<T extends Builder<T>> {
        protected Long id;

        public T id(Long id) {
            this.id = id;
            return self();
        }

        // 子类Builder必须实现此方法返回自身,保证链式调用
        protected abstract T self();
        public abstract BaseDTO build();
    }
}

// Movie类,继承BaseDTO并实现自己的Builder
class Movie extends BaseDTO {
    protected final String title;
    protected final Integer releaseYear;

    protected Movie(Movie.Builder<?> builder) {
        super(builder);
        this.title = builder.title;
        this.releaseYear = builder.releaseYear;
    }

    // Movie的泛型Builder,继承自BaseDTO.Builder
    static class Builder<T extends Builder<T>> extends BaseDTO.Builder<T> {
        protected String title;
        protected Integer releaseYear;

        public T title(String title) {
            this.title = title;
            return self();
        }

        public T releaseYear(Integer releaseYear) {
            this.releaseYear = releaseYear;
            return self();
        }

        @Override
        protected T self() {
            return (T) this;
        }

        @Override
        public Movie build() {
            return new Movie(this);
        }
    }

    // 快速创建Builder的静态方法
    public static Movie.Builder<?> builder() {
        return new Movie.Builder<>();
    }
}

// UserMovie类,继承Movie并新增专属字段,Builder继承Movie.Builder
class UserMovie extends Movie {
    private final Integer yourRating;
    private final boolean favorited;

    protected UserMovie(UserMovie.Builder builder) {
        super(builder);
        this.yourRating = builder.yourRating;
        this.favorited = builder.favorited;
    }

    // UserMovie的Builder,指定泛型为自身,确保链式调用流畅
    static class Builder extends Movie.Builder<UserMovie.Builder> {
        private Integer yourRating;
        private boolean favorited;

        public UserMovie.Builder yourRating(Integer yourRating) {
            this.yourRating = yourRating;
            return self();
        }

        public UserMovie.Builder favorited(boolean favorited) {
            this.favorited = favorited;
            return self();
        }

        @Override
        protected UserMovie.Builder self() {
            return this;
        }

        @Override
        public UserMovie build() {
            return new UserMovie(this);
        }
    }

    // 快速创建Builder的静态方法
    public static UserMovie.Builder builder() {
        return new UserMovie.Builder();
    }

    // 子类字段的Getter方法(私有终态字段需要暴露访问)
    public Integer getYourRating() {
        return yourRating;
    }

    public boolean isFavorited() {
        return favorited;
    }
}

需求一:返回包含子类字段的父类对象的方法

这里的核心逻辑是:父类类型的引用可以指向子类实例,所以我们可以写一个返回Movie类型的方法,但实际返回UserMovie的实例,这样这个Movie对象就天然包含子类的专属字段。

实现示例

/**
 * 返回包含用户专属字段的Movie对象(实际是UserMovie实例)
 */
public Movie getMovieWithUserSpecificFields(Long movieId, Integer userRating, boolean isFavorited) {
    // 这里可以替换为从数据库/接口获取真实数据的逻辑
    return UserMovie.builder()
            .id(movieId)
            .title("星际穿越")
            .releaseYear(2014)
            .yourRating(userRating)
            .favorited(isFavorited)
            .build();
}

如何访问子类字段

当你拿到这个Movie对象后,可以通过类型判断+向下转型来获取子类的专属字段:

// 调用方法获取Movie对象
Movie movie = getMovieWithUserSpecificFields(1001L, 5, true);

// 判断是否为UserMovie实例后转型访问字段
if (movie instanceof UserMovie) {
    UserMovie userMovie = (UserMovie) movie;
    System.out.println("你的评分:" + userMovie.getYourRating());
    System.out.println("是否收藏:" + userMovie.isFavorited());
}

需求二:实体到DTO对象的转换

假设我们有对应的数据库实体类(MovieEntity和UserMovieEntity),我们可以利用DTO的Builder来实现简洁的转换逻辑。

先定义实体类示例

// 电影实体类
class MovieEntity {
    private Long id;
    private String title;
    private Integer releaseYear;

    // Getter & Setter
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    public Integer getReleaseYear() { return releaseYear; }
    public void setReleaseYear(Integer releaseYear) { this.releaseYear = releaseYear; }
}

// 用户电影关联实体类
class UserMovieEntity {
    private Long id;
    private String title;
    private Integer releaseYear;
    private Integer yourRating;
    private boolean favorited;

    // Getter & Setter
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    public Integer getReleaseYear() { return releaseYear; }
    public void setReleaseYear(Integer releaseYear) { this.releaseYear = releaseYear; }
    public Integer getYourRating() { return yourRating; }
    public void setYourRating(Integer yourRating) { this.yourRating = yourRating; }
    public boolean isFavorited() { return favorited; }
    public void setFavorited(boolean favorited) { this.favorited = favorited; }
}

实现转换方法

可以写一个静态工具类,或者直接在DTO类中添加静态转换方法,这里用静态工具类示例:

class DTOConverter {
    // Movie实体转Movie DTO
    public static Movie convertToMovieDTO(MovieEntity entity) {
        return Movie.builder()
                .id(entity.getId())
                .title(entity.getTitle())
                .releaseYear(entity.getReleaseYear())
                .build();
    }

    // UserMovie实体转UserMovie DTO
    public static UserMovie convertToUserMovieDTO(UserMovieEntity entity) {
        return UserMovie.builder()
                .id(entity.getId())
                .title(entity.getTitle())
                .releaseYear(entity.getReleaseYear())
                .yourRating(entity.getYourRating())
                .favorited(entity.isFavorited())
                .build();
    }

    // 需求一结合:返回包含子类字段的父类DTO
    public static Movie convertToMovieWithUserFields(UserMovieEntity entity) {
        return convertToUserMovieDTO(entity); // 直接向上转型为Movie
    }
}

使用示例

// 模拟从数据库获取实体
UserMovieEntity userMovieEntity = new UserMovieEntity();
userMovieEntity.setId(1002L);
userMovieEntity.setTitle("盗梦空间");
userMovieEntity.setReleaseYear(2010);
userMovieEntity.setYourRating(5);
userMovieEntity.setFavorited(true);

// 转换为包含子类字段的Movie对象
Movie movie = DTOConverter.convertToMovieWithUserFields(userMovieEntity);

// 访问子类字段
if (movie instanceof UserMovie) {
    UserMovie userMovie = (UserMovie) movie;
    System.out.println("电影名称:" + userMovie.title); // Movie的字段
    System.out.println("你的评分:" + userMovie.getYourRating()); // UserMovie的字段
}

内容的提问来源于stack exchange,提问作者JONKI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:37:50