前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SOLID之LOD

SOLID之LOD

作者头像
码农戏码
发布2022-04-15 09:11:10
4330
发布2022-04-15 09:11:10
举报
文章被收录于专栏:DDDDDD

迪米特法则 Law of Demeter

LOD

最早出现于 1987年,由美国东北大学的伊恩·霍兰德(Ian Holland)提出。也叫做“最少知识原则”。

Each unit should have only limited knowledge about other units: only units “closely” related to the current unit. Or: Each unit should only talk to its friends; Don’t talk to strangers.

高内聚低耦合

我们设计的目标就是高内聚低耦合,是否高内聚关键在于封装性

看段代码:

代码语言:javascript
复制
String name = book.getAuthor().getName();

可以推断出这行代码是获得一部作品作者的名字。

正常都能写出这段代码,因为在同一模块下大多数代码都是同一个人写的,所以Book和Author两个类都清楚里面的细节。但如果是不同人写的呢?至少得问下别人,作者名字在哪个类?或者翻阅类中实现细节。

从接口设计角度,外部只能知道Book对象,而Book中关联的对象细节是不需要知道的,这正是封装性的体现,降低认知负载。

而这也正好违背了LOD原则。

不该有直接依赖关系的类之间,不要有依赖;

有依赖关系的类之间,尽量只依赖必要的接口。

迪米特法则是希望减少类之间的耦合,让类越独立越好。LOD功效正是指导我们能设计出高内聚、

所以上面的代码得改动一下Book类

代码语言:javascript
复制
class Book {
   public String getAuthorName(){
        return author.getName();
   }
}

谁是朋友?

既然LOD指出只跟自己的朋友交流,那得搞清楚谁是朋友?

对于一个类C,它拥有的一个方法称为M。方法M发送信息的目标对象必须为:

•M方法的参数对象,还有对自身的引用(被方法M创建的实例对象、被方法M调用的方法生成的实例对象、全局对象)。•类C的实例对象。

把上面的情况拆解开:

1.本身(this,self)2.方法M的参数对象(parameter)3.类C内实例变量引用的对象(instance variable)4.被方法M创建的对象 或 方法M调用的方法创建的对象5.如果实例变量是集合,集合中的对象(collection,aggregration)

示例

在正统的SOLID原则中,都不包含LOD原则,但它确实能很好地指导我们如何封装,达到高内聚的目标。

下面看两个常见到的问题作为示例,进一步理解这个原则。

流式API

上面提到的代码

代码语言:javascript
复制
String name = book.getAuthor().getName();

开始没有意识到违背LOD,但至少会有null情况,所以会改成

代码语言:javascript
复制
if(book != null) {
    Author author = book.getAuthor();
    if(author != null) {
        name = author.getName();
    }
}

如果有好几层,就会嵌套很多层。

但从JDK8之后,有了Optional,代码就变成了

代码语言:javascript
复制
name = Optional.ofNullable(book).map(Book::getAuthor).map(Author::getName);

虽然这样子很简洁地解决了null的问题,但是不是一样违背LOD呢?

延伸一下,是不是链式调用都违反了LOD,毕竟形式上的确很像,一个连接符接着一个连接符。

代码语言:javascript
复制
Report report = new ReportBuilder()
  .withBorder(1)
  .withBorderColor(Color.black)
  .withMargin(3)
  .withTitle("Law of Demeter Report")
  .build();

如我们常见的builder方式,每次返回的都是self。根据“谁是朋友”的定义是允许的。这是简单的示例,但像上面的Optional呢?

每次Optional.map之后,其实并不是最初的Optional对象了,Stream也一样,每次返回的都是一个新的Stream对象。

怎么解释这种问题呢?这个问题其实有很多人提出疑问,大概有这么几种回答:

1、Stream shows that you are using it as intended by the Java language designers[1]

2、any standard library objects should be exempt from the Law of Demeter

3、All these laws/principles are rarely absolute and more guidelines than dogmas. In this case it might be about balancing LoD vs. KISS.[2]

所以结论是什么呢?

我想重要的还是共识,团队内的共识。就像在JDK7~JDK8的过渡期,团队中有先行者引入了stream新特性,很多成员看得头大,制定了团队公约,不要使用stream。但现在fluent interface已经很亲民了,自然团队对stream有更高的认同,有了共识,谁还会抵制它。

RESTful API

再扩展一下,看到很长的RESTful风格的url,这是不是也有违背LOD原则的嫌疑?

在RESTful API场景下,实体只有客户端和API提供者,API内部的实现细节也被API层屏蔽了,所以并不会违背LOD原则。

总结

LOD原则指导我们更好地封装,达到内聚性目标。但通过fluent interface,也认识到任何原则都是指导性,不可教条。考虑原则的同时,还得考虑ROI,而且还得与其它原则权衡,达到最适合的设计。

References

[1] Stream shows that you are using it as intended by the Java language designers: https://stackoverflow.com/questions/45491555/can-multiple-operations-with-streaming-break-the-law-of-demeter [2] All these laws/principles are rarely absolute and more guidelines than dogmas. In this case it might be about balancing LoD vs. KISS.: https://stackoverflow.com/questions/47347068/optional-monad-and-the-law-of-demeter-in-java [3] The Genius of the Law of Demeter: https://dzone.com/articles/the-genius-of-the-law-of-demeter [4] LOD原则的高明之处: https://www.zybuluo.com/XingdingCAO/note/913912

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农戏码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • LOD
  • 高内聚低耦合
  • 谁是朋友?
  • 示例
  • 流式API
  • RESTful API
  • 总结
    • References
    相关产品与服务
    Serverless HTTP 服务
    Serverless HTTP 服务基于腾讯云 API 网关 和 Web Cloud Function(以下简称“Web Function”)建站云函数(云函数的一种类型)的产品能力,可以支持各种类型的 HTTP 服务开发,实现了 Serverless 与 Web 服务最优雅的结合。用户可以快速构建 Web 原生框架,把本地的 Express、Koa、Nextjs、Nuxtjs 等框架项目快速迁移到云端,同时也支持 Wordpress、Discuz Q 等现有应用模版一键快速创建。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档