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

不可变类继承体系下类型安全复用防御拷贝方法的实现方案

实现方案(完全不需要使用clone())

核心思路是利用奇异递归泛型模式(CRTP)做编译期类型限定,强制子类实现拷贝构造逻辑,基类的通用属性修改逻辑可以在整个继承链复用,全程都是显式的对象构造,符合不可变类的设计规范。

第一步:改造基类结构

给基类增加递归泛型参数,限定返回值类型为子类本身,同时将所有属性声明为final(原代码的pageCond漏了final修饰,不符合不可变类要求),声明抽象拷贝方法强制子类实现:

public class PageQuery<T, E extends PageQuery<T, E>> {
    private final T queryFilter;
    private final PageCond pageCond;

    // 基类全参构造器
    public PageQuery(T queryFilter, PageCond pageCond) {
        this.queryFilter = queryFilter;
        this.pageCond = pageCond;
    }

    // 全继承体系复用的with方法,返回子类实例无需强转
    public E withPageCond(PageCond newPageCond) {
        // 复用现有queryFilter,仅替换pageCond
        return copy(this.queryFilter, newPageCond);
    }

    // 抽象拷贝方法,强制子类实现自身实例构造逻辑
    protected abstract E copy(T queryFilter, PageCond pageCond);

    // 省略getter方法
}

第二步:子类实现拷贝逻辑

子类只需要实现一次copy方法,所有父类的with*通用方法就可以直接复用,不需要重复写逻辑:

public class PageSortQuery<T> extends PageQuery<T, PageSortQuery<T>> {
    private final SortCond sortCond;

    // 子类全参构造器
    public PageSortQuery(T queryFilter, PageCond pageCond, SortCond sortCond) {
        super(queryFilter, pageCond);
        this.sortCond = sortCond;
    }

    @Override
    protected PageSortQuery<T> copy(T queryFilter, PageCond pageCond) {
        // 子类自身属性用当前实例的旧值,仅替换父类传入的通用属性
        return new PageSortQuery<>(queryFilter, pageCond, this.sortCond);
    }

    // 子类也可以扩展自己的with方法,格式保持统一
    public PageSortQuery<T> withSortCond(SortCond newSortCond) {
        return new PageSortQuery<>(getQueryFilter(), getPageCond(), newSortCond);
    }

    // 省略getter方法
}

调用效果验证

编译期类型安全,调用父类方法直接返回子类类型,不需要手动强转:

PageSortQuery<User> originQuery = new PageSortQuery<>(userFilter, oldPageCond, sortCond);
// 直接调用父类继承的withPageCond,返回值就是子类类型
PageSortQuery<T> newQuery = originQuery.withPageCond(newPageCond);

方案优势

  • 完全避免了clone()的问题:不需要实现Cloneable接口,不会出现浅拷贝风险,所有构造逻辑都是显式可控的
  • 通用逻辑完全复用:父类新增其他with*通用方法时,所有子类不需要修改任何代码就能直接使用
  • 编译期类型校验:不会出现类型转换异常,符合强类型语言的设计规范

如果不想用递归泛型,也可以采用协变返回的简化方案:基类withPageCond返回PageQuery,子类重写方法时返回子类类型,缺点是调用父类方法后需要手动强转,易用性略差。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 03:57:00