基于REST/JPA查询结果,实现运行时装饰元素的列表是否有标准模式?
对应的标准设计模式:装饰器模式(Decorator Pattern)
你需要的场景完全契合装饰器模式的核心设计目标:在运行时动态为对象添加额外职责(这里的额外属性/数据),同时不修改原有对象的结构,也无需复制整个结果列表。
核心思路
装饰器模式通过“包装”原有对象的方式,在不改变原类代码的前提下,为对象新增属性或行为。针对你的场景:
- 定义与原对象(如
Person)一致的接口,确保装饰后的对象能无缝替代原对象 - 实现装饰器类,持有原对象的引用,按需添加额外属性(支持懒加载,避免提前批量查询带来的性能损耗)
- 可选实现列表级装饰器,无需复制原列表,动态返回装饰后的元素
代码示例(Java 技术栈,适配JPA/REST场景)
1. 定义统一接口
首先为原对象和装饰器定义共同接口,保证类型兼容:
public interface PersonInfo { String getId(); String getName(); // 原Person类的其他核心方法 }
2. 原对象实现接口
public class Person implements PersonInfo { private String id; private String name; // 构造器、Getter、Setter @Override public String getId() { return id; } @Override public String getName() { return name; } }
3. 实现属性装饰器
装饰器类持有原对象引用,新增假期配额属性并实现懒加载:
public class HolidayQuotaPersonDecorator implements PersonInfo { private final PersonInfo delegate; private Integer holidayQuota; private final HolidayQuotaService quotaService; // 查询假期配额的服务 public HolidayQuotaPersonDecorator(PersonInfo delegate, HolidayQuotaService quotaService) { this.delegate = delegate; this.quotaService = quotaService; } // 委托原对象的方法 @Override public String getId() { return delegate.getId(); } @Override public String getName() { return delegate.getName(); } // 新增的额外属性,懒加载:用到时才查询 public Integer getHolidayQuota() { if (holidayQuota == null) { holidayQuota = quotaService.getQuotaByPersonId(delegate.getId()); } return holidayQuota; } }
4. 无复制的列表装饰器
如果要完全避免复制原列表,可以实现一个包装原列表的装饰器,动态生成装饰后的元素:
public class DecoratedList<T, U> extends AbstractList<U> { private final List<T> originalList; private final Function<T, U> decorator; public DecoratedList(List<T> originalList, Function<T, U> decorator) { this.originalList = originalList; this.decorator = decorator; } @Override public U get(int index) { return decorator.apply(originalList.get(index)); } @Override public int size() { return originalList.size(); } }
5. 使用方式
// 从REST/JPA获取原列表 List<Person> originalPersons = restPersonClient.getPersons(); // 生成装饰后的列表,无需复制原数据 List<PersonInfo> decoratedPersons = new DecoratedList<>( originalPersons, person -> new HolidayQuotaPersonDecorator(person, holidayQuotaService) ); // 访问元素时才会触发装饰和配额查询 PersonInfo personWithQuota = decoratedPersons.get(0); System.out.println(personWithQuota.getHolidayQuota());
其他可选思路
- 代理模式:与装饰器模式类似,但更侧重对原对象的访问控制,若你的场景仅需添加属性,装饰器更贴合
- 转换器模式:若允许创建新的DTO对象(复制原数据),可以将原对象转换为带额外属性的DTO,但不符合你“避免复制”的需求
内容的提问来源于stack exchange,提问作者p4w3l
相关产品推荐
相关产品推荐

