不可变类继承体系下类型安全复用防御拷贝方法的实现方案
实现方案(完全不需要使用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
相关产品推荐
相关产品推荐

