(联合国)酷代码的易碎定律:Demeter定律(带有TypeScript中的示例)

当我了解这些原理时,我的代码的灵活性就达到了x2,并且决定了实体设计的速度x5。



如果SOLID是用于编写质量代码的一组原则,则Demeter法则(LoD)告诉不要问(TDA)是实现SOLID的特定技巧。



今天我们将讨论迪特耳特法则(“迪特尔法则”)。



夸张的



该原则有助于确定:“我将如何获取/修改嵌套对象”-适用于可以用属性和方法定义“类”的语言。



通常,当我们从某个地方(例如从HTTP请求)接收到实体``a''的ID,然后将其跟随到数据库中时,通常需要一种情况,即我们需要通过调用方法``方法''从实体`a`获取/更改实体``b''。



因此,维基百科说:

`abMethod()`代码违反了Demeter定律,并且`a.Method()`代码正确。




用户具有评论的帖子。您想收到“最新评论”。



您可以提交以下文件:



const posts = user.posts
const lastPostComments = posts[posts.length-1].comments


或像这样:



const userLastPostComments = user.getPosts().getLast().getComments()


问题:代码了解嵌套数据的整个层次结构,并且如果此层次结构发生更改/扩展,则无论在何处调用此链,都必须进行更改(重构代码+测试)。



要解决此问题,请应用LoD:



const userLastPostComments = user.getLastPostComments()


但是已经在` User`中写了:



class User {
  // ...
  getLastPostComments(): Comments {
    return this.posts.getLastComments()
  }
  // ...
}


同样的故事,加上评论。我们是从:



const newComment = new Comment(req.body.postid, req.body.content)
user.getPosts().addComment(newComment)


或者,如果您想炫耀您的诊断:



const newComment = new Comment(req.body.postid, req.body.content)
const posts = user.posts
posts[posts.length-1].comments.push(newComment)


变成这个:



const posts = user.addCommentToPost(req.body.postid, req.body.content)


对于` User`



class User {
  // ...
  addCommentToPost(postId: string, content: string): void {
    // The cleanest
    const post = this.posts.getById(postId)
    return post.addComment(content)
  }
  // ...
}




澄清:可以在用户帖子之外创建新评论,这完全取决于应用程序逻辑的排列方式,但是越接近实体所有者(在这种情况下,就是帖子)就越好。



它有什么作用?



我们隐藏了实现细节,并且如果有更改/层次结构扩展(例如,职位将不仅位于``职位属性''中),您只需重构方法getLastPostComments` /` addCommentToPost`并重写单元测试仅此方法。



有什么缺点



很多额外的 码。



在小型项目中,大多数方法只是` getter` /` setter`



何时使用



(1)LoD适用于具有深/复杂/合并连接的模型,实体,集合或类。



(2)代码需要这样的概念:“获取最后一篇文章的评论”-并且您的文章不在1st属性中,而是在2个或更多属性中,那么,您当然需要制作` getLastPostComments`方法并合并具有不同属性的多个属性帖子。



(3)在转换(更改,创建,删除)数据时,我尝试尽可能多地使用此原理。检索数据的频率也降低了。



(4)基于常识。



生活骇客



许多人开始担心代理方法的数量,因此有一个简化:



为了不创建无限数量的代理方法,可以在顶级类(在我们的例子中为User)中使用LoD,并且在实现中已经违反了法律。例如:



const userLastPostComments = user.getLastPostComments()

class User {
  // ...
  getLastPostComments(): Comments {
    //   LoD,    Post    
    const lastPost = this.posts[this.posts.length-1]
    return lastPost.comments
  }
  // ...
}




随着时间的流逝,如果`post`增长了,有可能使它成为`getLast()`或`getLastComments()`的方法,而这将不需要很多重构。



为此需要什么



如果您具有适当的实体依赖关系树/层次结构,则LoD效果很好



读什么



(1)https://qna.habr.com/q/44822

确保阅读所有评论和评论(在评论Vyacheslav Golovanov之前SLY_G),请记住同时存在正确和错误的示例

(2)https://ru.wikipedia.org/wiki/Zakon_Demeter

(3)文章



聚苯乙烯



我可能会搞砸一些细节/示例,或者解释得不够清楚,因此请在您注意到的评论中写下来,然后进行更改。都好。



PPS



阅读这行评论,在其中巢穴 我们将在本文中更详细地分解一个未完全点亮的盒子



All Articles