Wetts's blog

Stay Hungry, Stay Foolish.

0%

代码整洁之道-第8章-边界

使用第三方代码

在接口提供者和使用者之间,存在与生俱来的张力。第三方程序包和框架提供者追求普适性,这样就能在多个环境中工作,吸引广泛的用户。而使用者则想要集中满足特定需求的接口。这种张力会导致系统边界上出现问题。

以java.util.Map为例。应用程序可能构造一个Map对象并传递它。我们的初衷可能是Map对象的所有接收者都不要删除映射图中的任何东西。但是Map中正好有一个clear()方法。Map的任何使用者都能清楚映射图。或许设计惯例是Map中只能保存特定的类型,但Map并不会可靠地约束存于其中的对象的类型。使用者可随意往Map中塞入任何类型的条目。

可以通过泛型来规定传入参数的类型。但是超出所需/所愿的功能问题,仍未得到解决。

在系统中不受限制的传递Map<Integer, Sensors>的实体,意味着当到Map的接口被修改时,有许多地方都要跟着改。你或许会认为这样的改动不太可能发生,不过,当Java 5加入对泛型的支持时,的确发生了改动。

使用Map的更整洁的方式大概如下。Sensors的用户不必关心是否用了泛型,那将是实现细节才关心的。

1
2
3
4
5
6
7
public class Sensors {
private Map sensors = new HashMap();

public Sensors getById(String id) {
return (Sensors) sensors.get(id);
}
}

边界上的接口(Map)是隐藏的。它能随来自应用程序其他部分的极小的影响而变动。对泛型的使用不再是一个大问题,因为转换和类型管理是在Sensors类内部处理的。

我们并不建议总是以这种方式封装Map的使用。我们建议不要将Map(或者边界上的其他接口)在系统中传递。如果你使用类似Map这样的边界接口,就把它保留在类或近亲类中。避免从公共API中返回边界接口,或将边界接口作为参数传递给公共API。


我们通过代码中少数几处引用第三方边界接口的位置来管理第三方边界。可以像我们对待Map那样包装它们,也可以使用Adapter模式将我们的接口转换为第三方提供的接口。采用这两种方式,代码都能更好地与我们沟通,在边界两边推动内部一致的用法,当第三方代码有改动时修改点也会更少。