尽管有些人可能讨厌“可选方法”,但在许多情况下,它们可能比高度隔离的接口提供更好的语义。除其他事项外,它们还使对象有可能在其生命周期中获得能力或特性,或者使对象(尤其是包装对象)在构造时可能不知道应报告的确切能力。
虽然我几乎不会称赞Java收集类的优秀设计为典范,但我建议一个好的收集框架应在其基础上包括大量可选方法,以及向收集器询问其特性和能力的方法。这样的设计将允许单个包装器类与各种集合一起使用,而不会意外地遮盖基础集合可能具有的功能。如果方法不是可选的,则对于集合可能支持的功能的每种组合,都必须有一个不同的包装器类,否则在某些情况下某些包装器将无法使用。
例如,如果一个集合支持按索引写一个项目,或在末尾附加项目,但不支持在中间插入项目,那么想要将其封装在包装器中的代码将记录在其上执行的所有操作,则需要一个版本提供了所支持功能的确切组合的日志记录包装程序,或者如果没有可用的包装程序,则必须使用支持附加或按索引写入但不同时支持两者的包装程序。但是,如果统一的集合接口将所有三个方法都提供为“可选”,但随后包括指示哪些可选方法将可用的方法,则单个包装器类可以处理实现功能的任意组合的集合。当被问及它支持哪些功能时,包装器可以简单地报告封装的集合所支持的内容。
请注意,“可选功能”的存在在某些情况下可能允许聚合集合以某些方式实现某些功能,而这些方式的效率要比通过实现的存在来定义功能的方式更为有效。例如,假设使用了一种concatenate
方法来形成另外两个对象的复合集合,其中第一个碰巧是具有1,000,000个元素的ArrayList,最后一个是只能从头开始迭代的二十个元素的集合。如果复合集合被要求提供第1,000,013个元素(索引1,000,012),则可以询问ArrayList包含多少个项(即1,000,000),从请求的索引中减去该项(产量12),从第二个元素读取和跳过十二个元素集合,然后返回下一个元素。
在这种情况下,即使复合集合没有立即返回按索引返回项目的方式,但要求复合集合中第1,000,013个项目比单独读取1,000,013个项目并忽略除最后一个项目之外的所有项目要快得多一。