绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
代码整洁之道【7】-- 边界
2023-07-04 18:05:09

这一章书中全是理论性的东西,再加上中文翻译肯定有词不达意的地方(并未有意冒犯译者,sry),初读起来并没有理解,遂仔细思考后又读了两遍才敢总结。

作者在本章提到“边界”的概念,我个人的理解是:使用外部代码(第三方库提供的API、或者其他模块的服务)与自身项目代码结合的时候,自身项目调用外来代码以及外来代码提供的功能,这两部分代码就是边界。如果干净利落的将这些代码整合,就能保持软件边界的整洁。

一、使用第三方代码(良好的实践范例)

第三方jar包和框架提供者追求通用性,这样就能在多个环境下工作,吸引更多的用户。而使用者则想要集中满足特定需求的接口,这样方便开发需求。正是因为服务提供者和使用者的目标的差异,导致了在系统边界上可能会出现问题。

举个例子,以java.util.Map为例。Map中拥有丰富的功能(这对应了上面说的第三方jar包和框架提供者追求通用性)。但是,这也会付出一些代价。比如,应用程序可能构造一个Map对象并到处传递它的引用。 假设我们原来设计的初衷是:Map对象的所有接收者都不要删除映射里的东西,但是实际情况却是任何Map的使用者都能使用clear()方法清空Map中的映射。

接下来用代码演示一下。假如你的应用程序需要一个能存储Sensor的Map,那一般可以这么写:

Map sensors = new HashMap();

当代码的其它部分需要访问这些sensor时,可以这样做:

Sensor s = (Sensor) sensors.get(sensorId);

这种获取元素的方式虽然可行,但是调用端承担了从Map对象中取得对象并将其转换成正确类型的职责,并非整洁的代码。可以通过使用泛型,让代码变整洁:

Map<Sensor> sensors  = new HashMap<Sensor>();
...省略put操作
Sensor s = sensors.get(sensorId);

在系统中无节制的传递Map对象的引用,意味着如果Map提供的接口被修改时,有非常非常多的地方需要跟着改动。例如,Java 5加入对泛型的支持时,Map接口的确发生了变动。

所以在本例中,使用Map的更整洁的方式大致如下:
sensors的用户不关心是不是使用了泛型,把类型转换等操作提取到Sensor类中作为一个方法,这样在接口发生改变时,我们只需要修改这一个方法即可。

public class Sensors {
    private Map sensors = new HashMap;
    public Sensor  getById(String id) {
        return (Sensor) sensors.get(id);
    }
}

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

二、使用尚不存在的代码

协同开发过程中经常会碰到代码调用的API还没有处理好的情况,在这中情况下我们定义好我们的接口和方法。一旦API被定义出来,可以使用适配器模式来进行衔接。Adapter封装了与API的互动,也提供了一个当API发生变动时需要改动的地方。

读者可以自行了解一下Adapter设计模式。记住这种应用场景。

三、整洁的边界

在我们的代码中应该尽量少的了解第三方代码中的特定信息,也就需要尽量去封装好第三方边界接口。可以像封装Map那样,也可以使用适配器模式将我们的接口转换为第三方的接口。采用这两种方法,代码都能更好地与我们沟通,在边界两边推动内部一致的用法。这样当第三方代码改动的时候,我们的代码修改点也会更少。

参考
《代码整洁之道》
分享好友

分享这个小栈给你的朋友们,一起进步吧。

代码整洁之路
创建时间:2023-07-04 18:03:33
代码整洁之路
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • LCR_
    栈主

小栈成员

查看更多
  • jiakangh
  • lypaser
戳我,来吐槽~