Java 部分可变的API类,带有通用变量保持器供客户端使用
我正在构建一个API。它的一个功能是执行一些资源分析(想象一个文档、URI或DB,不重要的是什么)并返回一个Java 部分可变的API类,带有通用变量保持器供客户端使用,java,api,design-patterns,immutability,Java,Api,Design Patterns,Immutability,我正在构建一个API。它的一个功能是执行一些资源分析(想象一个文档、URI或DB,不重要的是什么)并返回一个列表,其中Finding是一个POJO。我希望Finding在从API返回时是不可变的,所有数据都是由API返回的,但是,为了方便客户端,我希望有一个setUserNote(String)方法 这样做的原因是,客户机可以获得查找s的列表,它可以在使用setUserNote将自己的数据保存在对象本身中时处理这些列表,就像普通的注释一样。我认为这比客户机必须扩展Finding来添加一个变量或将
列表,其中Finding
是一个POJO。我希望Finding
在从API返回时是不可变的,所有数据都是由API返回的,但是,为了方便客户端,我希望有一个setUserNote(String)
方法
这样做的原因是,客户机可以获得查找
s的列表,它可以在使用setUserNote
将自己的数据保存在对象本身中时处理这些列表,就像普通的注释一样。我认为这比客户机必须扩展Finding
来添加一个变量或将其封装为实例变量,然后ExtendedFinding.someMethod(){返回this.Finding.someMethid();}
来查找中的每个方法更方便。此外,至少可以说,对于客户机来说,用他从API获得的查找来构造扩展查找,会很麻烦。这就是为什么我计划只给他们一个方便使用的领域
问题:
这是一个糟糕的设计吗?为什么?我以前从未做过类似的事情,也没有见过API类为了方便客户机而附带任意数据保持器变量
假设这是一个糟糕的设计。什么是一种适用的设计模式,可以方便地传播查找以构建客户端的ExtendedFinding?当然,您可以使用类似publicExtendedFinding(Finding){/*copy vars one-by-one*/}
的东西,但这远远不够优雅
这不一定是糟糕的设计。这听起来很少见。在设计API时,务必牢记API的可能用途,但我觉得这有点过分了:
- 它打破了单一责任原则:该类现在既可以表示
发现
,也可以作为用户指定数据的容器
- 它将用户限制为
String
notes,而不是任意对象。例如,如果需要,他们将无法使用地图或自定义POJO。(不过,使用泛型可以很容易地解决这个问题。)
更好的解决方案可能是在Finding
类中定义equals
和hashCode
方法。通过这种方式,这些对象可以用作映射的键,用户可以将其注释存储在API之外
另一种解决方案可能是定义一个新类来表示查找
和用户注释对。这比在不可变的查找
类中存储注释有更清晰的“感觉”,但增加的复杂性可能使其不值得付出努力。哪种解决方案最好实际上取决于具体情况;答案没有对错之分
(顺便说一句,final
关键字并没有使类不可变。它只是意味着你不能为它定义子类。你可以创建可变的final类——举个例子)首先你的第三点,final
决不能使类不可变——它意味着类不能从中继承。因此,您不能扩展final
类
对于您的主要问题,为什么不将POJO强制转换为接口
,并返回该接口的列表,而不是底层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;
}
公共静态接口查找{
//所有公众人物
void setUserNote();
}
静态最终类FindingImpl实现查找{
@凌驾
public void setUserNote(){
抛出新的UnsupportedOperationException(“尚未受支持”);//若要更改生成的方法体,请选择“工具”“模板”。
}
}
private final Collection findingpimpls=new ArrayList();
公众收集{
最终收集结果=新的ArrayList();
对于(最终FindingImpl fi:findingImpls){
调查结果。添加(fi);
}
返回结果;
}
我很困惑。如果你把一个发现归还给我,你认为不可改变的话,那我怎么能给这个物体注入一个音符呢?假设其他人也会看到同样的发现,不是吗
这里的正确答案是,您应该有另一个类:FindingComment,带有注释者id、查找id和时间戳
你的直觉是,扩展类来吸引评论肯定是正确的 听起来像是userNote
不应该在Finding
中。但我仍然想知道这是否是一种反模式(用户便利数据包变量,其中所有其他类变量都是只读的)。当然,String
只是为了简单起见。它可能是一个对象
或者是你的第一个项目的一些集合,注释肯定是这个发现的一个属性,类似于用户添加的附录。有点像你买了一本参考手册,它的末尾有10页空白供你输入你自己的笔记。是的,我没有回答这个易变的问题。对不起,我对最终版感到困惑。我假设查找
中的每个变量都需要声明为final,但usernote除外我不明白为什么-如果最终用户由于接口
(所有变量都是私有的
)而只能访问getter而不能访问setter,那么就没有理由将变量设置为final
。这是调用封装。