我正在构建一个API。它的一个功能是执行一些资源分析(想象一个文档,URI或DB,不重要的是什么)并返回List<Finding>
Finding
是POJO。我希望Finding
从API返回后是不可变的,包含API返回的所有数据,但是,为了方便客户,我希望有一个setUserNote(String)
方法。
它的原因是客户端获得Finding
的列表,它可以在使用setUserNote
将其自己的数据保存在对象本身时处理它们,就像一个简单的注释。我认为这将是一个简洁的方便,最好是客户端必须扩展Finding
只是添加一个变量或将其封装为实例变量,然后ExtendedFinding.someMethod() { return this.finding.someMethid(); }
为Finding
中的每个方法。此外,至少可以说,客户从API获得的ExtendedFinding
中构建Finding
会很麻烦。这就是为什么我打算简单地给他们一个他们可以用来方便的领域。
问题:
这是一个糟糕的设计,为什么?我之前从未做过这样的事情,也没有看到API类带有任意数据持有者变量以方便客户。
让我们说这是一个糟糕的设计。什么是适用的设计模式,以便轻松传播Finding由客户端构造ExtendedFinding?当然,你可以拥有像公共ExtendedFinding(Finding) { /* copy vars one by one */ }
这样的东西,但这远非优雅
答案 0 :(得分:1)
这不一定是糟糕的设计。但这听起来并不常见。重要的是要记住API在设计时的可能用途,但我觉得这有点太过分了:
Findings
和表示为用户指定数据的容器的工作。String
个音符而不是任意对象。例如,如果需要,他们将无法使用Map或自定义POJO。 (但这很容易使用泛型来修复。)更好的解决方案可能是定义equals
类中的hashCode
和Finding
方法。通过这种方式,这些对象可以用作Map
的键,用户可以将其注释存储在API之外。
另一个解决方案可能会定义一个新类来表示Finding
和用户注释对。这比在其他不可变的Finding
类中存储笔记有一个更清晰的“感觉”,但增加的复杂性可能使它不值得努力。哪种解决方案最好取决于具体情况;没有正确或错误的答案。
(顺便说一句,final
关键字不会使类不可变。它只是意味着你不能为它定义子类。你可以创建最终的可变类 - 例如{{3 }})
答案 1 :(得分:1)
首先,你的第三点,final
决不会使一个类不可变 - 它表示该类不能继承。因此,您无法extend
final
类。
对于您的主要问题,为什么不将POJO转换为interface
并返回该列表而不是基础POJO。然后,您可以将实际的POJO类包设为私有,以便客户端无法将其转换回来:
public static interface Finding {
//all public getters
void setUserNote();
}
static final class FindingImpl implements Finding {
@Override
public void setUserNote() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
private final Collection<FindingImpl> findingImpls = new ArrayList<>();
public Collection<Finding> getFindings() {
final Collection<Finding> findings = new ArrayList<>();
for (final FindingImpl fi : findingImpls) {
findings.add(fi);
}
return findings;
}
答案 2 :(得分:0)
我很困惑。如果你向我发回一个Finding,那你认为它是不可变的,那么对于我来说,如果能够将一个注释一次注入该对象,它是如何让我感觉到的?推测是其他人可能会得到相同的结果,不是吗?
这里的正确答案是你应该有另一个类:FindingComment,包括评论者的id,Finding的id和时间戳。
你将你的课程扩展到评论的本能肯定是正确的!