在Collection、Serie、Card类关系中,如何正确生成Card的复合值?
问题解答
不建议给Card类添加额外属性存储这个复合值,原因很直接:
- 数据冗余:复合值是上层Collection的id、Serie的name与Card自身id的拼接结果,并非Card的固有属性,硬存进去属于冗余数据。
- 一致性风险:如果Collection的id或Serie的name发生变更,必须同步更新所有关联Card里的复合属性,很容易出现漏改情况,维护成本高。
- 违反单一职责:Card的职责就是封装自身的id和name,上层关联的信息不属于它的管辖范畴。
更优的实现方式有这几种:
1. 在UI显示层动态拼接
直接在需要展示的地方,拿到对应的Collection、Serie和Card对象,实时拼接复合值即可,无需修改领域模型:
// 假设已获取到当前的collection、serie、card实例 String compositeValue = collection.id + "-" + serie.name + "-" + card.id; // 将compositeValue和card.name一起传给界面组件展示
2. 在关联的上层类中封装生成逻辑
如果希望把拼接逻辑封装起来,避免在UI层写过多业务相关代码,可以给Serie类添加对所属Collection的引用,然后提供生成复合值的方法:
先调整Serie类:
class Serie { final String id; final String name; final List<Card> cards; final Collection collection; // 添加父级引用 public Serie(String id, String name, List<Card> cards, Collection collection) { this.id = id; this.name = name; this.cards = cards; this.collection = collection; } // 生成当前Serie下某个Card的复合值 public String generateCardCompositeValue(Card card) { return collection.id + "-" + this.name + "-" + card.id; } }
之后在需要的时候,直接调用serie.generateCardCompositeValue(card)就能得到结果,逻辑都封装在Serie里,符合对象的职责边界。
3. 使用DTO专门处理界面展示数据
如果界面需要的展示字段比较复杂,可以创建一个专门的DTO(数据传输对象),把界面需要的所有字段封装进去,在服务层或UI层完成领域模型到DTO的转换:
// 用于界面展示的DTO class CardDisplayDTO { private final String cardName; private final String compositeValue; public CardDisplayDTO(String cardName, String compositeValue) { this.cardName = cardName; this.compositeValue = compositeValue; } // getter方法 public String getCardName() { return cardName; } public String getCompositeValue() { return compositeValue; } } // 转换示例 Card card = ...; Serie serie = ...; Collection collection = ...; CardDisplayDTO displayDTO = new CardDisplayDTO( card.name, collection.id + "-" + serie.name + "-" + card.id ); // 把displayDTO传给界面展示
这种方式能彻底把领域模型和UI展示数据隔离开,领域模型保持纯净,专注于业务逻辑,DTO则专门适配界面需求。
总的来说,优先选择动态拼接或者DTO的方式,既能避免冗余和一致性问题,也能保持代码的整洁性。
内容的提问来源于stack exchange,提问作者Manuel
相关产品推荐
相关产品推荐

