我想知道好的合同在哪里结束,偏执狂开始了。 真的,我只是不知道开发人员应该关心什么以及他应该忽略什么:)
假设我有一个包含值的类,比如java.lang.Integer。它的实例由其他对象(MappedObjects)(一对多或多对多)聚合,并且经常在MappedObjects的方法中使用。出于性能原因,我还在TreeMap中跟踪这些关系(guava MultiMap,无所谓),以便能够快速迭代绑定到某些Integer键范围的MappedObjects。 因此,为了使系统保持一致状态,我应该修改MappedObject.bind(整数整数)方法来更新我的Map,如:
class MappedObject {
public void bind (Integer integer) {
MegaMap.getInstance().remove(fInteger, this);
fInteger = integer;
MegaMap.getInstance().add(fInteger, this);
}
...
private Integer fInteger;
}
我可以使用这个最终方法创建抽象的MappedObject类,强制其他人继承它,但它很粗鲁。如果我将MappedObject定义为方法bind()的接口并提供骨架实现 - 其他开发人员可能稍后忘记将其包含在对象中并自己实现方法而不进行Map更新。
答案 0 :(得分:4)
是的,你应该强迫人们用你的代码做正确的事。让人们做错事的一个很好的例子是servlet方法 init(ServletConfig config),它希望你自己存储servlet配置,但很明显,很多人忘记存储配置,并且在运行servlet时无法正常工作。
在定义API时,您应始终遵循开放式原则,您的类应该打开以进行扩展并关闭以进行修改。如果您的类必须像这样工作,您应该只在有意义的地方打开扩展点,所有其他功能都不应该可用于修改,因为它可能会在将来导致实现问题。
答案 1 :(得分:1)
首先关注功能并将所有不必要的东西抛在身后。顺便说一句,你不能禁止反思,所以不要过分担心滥用。另一方面,您的API应该清晰明了,以便用户能够清楚地了解它们应该做什么以及它们不应该做什么。
答案 2 :(得分:1)
至少你应该做所有可以防止错误但却不费吹灰之力的东西。
例如:如果不允许变量为null,则使用原始类型(int
)而不是包装器(Integer
)。
所以在你的bind
方法中。如果您没有打算绑定null
,请使用int
代替Integer
作为参数类型。
答案 3 :(得分:1)
我会说你的课程应该尽可能简单地使用。
如果您允许开发人员覆盖方法,您肯定应该尽可能地记录合同。在这种情况下,开发人员选择覆盖一些基本功能,因此负责提供符合合同的实现。
如果您不希望开发人员覆盖部分功能 - 出于安全原因,如果没有合理的替代方案等 - 只需将该部分作为最终部分。在您的情况下,bind方法可能如下所示:
class MappedObject {
public final void bind (Integer integer) {
MegaMap.getInstance().remove(fInteger);
internalBind( integer );
MegaMap.getInstance().add(fInteger);
}
protected void internalBind( Integer integer ) {
fInteger = integer;
}
...
private Integer fInteger;
}
在这里,您允许开发人员覆盖internalBind()
方法,但请确保bind()
将执行映射。
总结:尽可能简单地使用和扩展类,并且没有开发人员复制大量的样板代码(如你的情况下的地图更新),以防他只想覆盖一些基本的功能(如实际绑定)。
答案 4 :(得分:0)
如果您认为您的API用户很愚蠢,则应禁止错误使用。否则你不应该阻挡他们做他们需要做的事情。
类和方法的多重化和良好命名应指明如何使用您的API。