写在文章前:

  或许你写过无数代码,参与过很多大型系统的设计,但,你是否曾经思考过,你的设计可扩展、易维护么,在高速变化的互联网世界里,它能经得起这种急速变化的考验么?如果你没想过这些问题,那请先放下你那些牛逼的梦想,放下你的高傲,好好去理解、回味设计六大原则和23种设计模式,因为它们是你腾飞的基石。今天,我勇敢的尝试翻译一篇有关设计原则的经典论文,希望对大家有帮助。(翻译是一项很费时、费精力的活,而且博主英语水平也不是特别好,翻译时多采用意译,见谅)

前言

  在我读大学的时候,我的一个教授说每个程序员都有一个“装满各种小技巧的包”,这些小技巧,也就是解决问题的方法,在我们的个人经历中,会一遍又一遍的用到。他说,他的工作就是“把更多的小技巧装入我们的包里”。他所说的“小技巧”也就是如设计模式和设计风格(原文为idioms)。

  这篇论文要讨论的是一个我特别喜欢的“小技巧”。相对于被划为设计模式(经管常被划分为设计模式),把它划为设计风格可能更合适。在理解了这个设计风格并知道怎么使用它,我相信你的代码会更优雅、更不容易出错,且更易维护。我马上要讲述一个如何减少你代码中对象耦合的方法。这个方法有一个很棒的名字:迪米特法则

  

  现在我们假设有一个送报的小孩,他从他的顾客那里得到送报的钱。让我们为顾客定义一个类,几行代码表示送报小孩从顾客收钱,和一个送报小孩会执行的一个代码片段。

  

编写我们的代码

  好,让我们开始写顾客这个类。顾客类可能有个姓和名,可能有一个银行账户,或者购物地址等。为了例子的简单考虑,我们定义了一个简单的顾客类。

  

  考虑到倒霉的长度,我们省略了setters。从这个例子看,很显然我们还需要定义一个钱包类:

  

  好了,这是一个简单的钱包。以后可能给它添加各种数据结构,但这个例子,这个钱包足够了。

  现在利用这些,我们可以开始做一些有用的事了。让我们的送报小孩按响门铃,然后向顾客要求送报的报酬。如果我们把这写成代码,代码如下:

  

  这段代码表示送报小孩从顾客那拿到钱包,检查钱包以确保钱够,然后把钱从顾客钱包取出,放到自己钱包。

  

为什么这样很糟糕

  那么,这段代码糟糕在哪?好,让我们把这段代码用真实的生活场景还原。

  很显然,当送报小孩索要报酬时,顾客直接让小孩从自己的口袋取出钱包,并从钱包里拿走报酬。

  我不知道你会不会这样,反正我是很少让人拿走我的钱包。在现实中,上面的场景会遇到很多困难,更不用说相信那小孩很诚实,只拿走自己应得的报酬。如果以后钱包有信用卡啥的,他还能拿走信用卡。但是,这个问题的本质是,“小孩知道了更多他不需要知道的信息”

  那是一个很重要的概念。“送报小孩”这个类现在知道顾客有个钱包,而且还能操作它。当我们编译小孩这个类,我们还需要顾客和钱包这两个类。这三个类紧紧的耦合在了一起。如果我们改变钱包类,我们可能还需要修改其他两个类。

  还有一个经典的难题可能会遇到。如果顾客的钱包被偷了,那会发生什么?在我们这个例子中,或许昨晚有个贼就偷了这个钱包,然后有人把代码修改了,把钱包置为null,如下:

  victim.setWallet(null);

  这看起来像是一个很合理的假设。但是对于我们的送报小孩类呢?回头看看代码。我们假设钱包是存在的!我们的代码执行时将抛出空指针异常。

  我们可以在任何方法调用钱包类之前,检查它是否为空,但这会使我们的代码更乱。而真实场景会更坏--“如果我的顾客有钱包,就看看钱包里有多少钱……如果他能付钱,拿走钱”。很显然,我们被弄晕了。

修改原始代码

  解决这个问题的更合适的方式是采用符合现实场景的方法:“当小孩来到门前要求报酬时,顾客不会把钱包交给小孩,而小孩甚至都不需要知道顾客有个钱包”。

  

  注意,顾客不再有"getWallet()"方法了,但是他有一个getPayMent方法。让我们看看小孩的:

  

为什么现在更好

  首先,现在的模型更好的符合现实世界的情况。小孩现在是向顾客索要报酬,而没有机会拿到钱包。

  其次,钱包现在可以改变了,但小孩和这种变化彻底隔离开来了。如果钱包的被偷了,顾客会换个钱包,但只要顾客提供的接口保持不变,顾客的客户端不会关心顾客是否换了一个新钱包。代码变得更易维护了。

  第三,可能也是最面向对象的理由,我们可以随意改变'getPayment()'的实现了。在第一个例子,我们假设顾客有一个钱包,这导致了我们讨论的空指针异常。在现实世界里,当小孩来到门前,我们的顾客可能从抽屉里取出钱,或者从室友那借。但所有这些业务逻辑,小孩都不需要关心了。所有这些都在'getPayment()'中实现,并且在将来可以改变而不影响小孩的代码。

  

你也可以听起来更智慧

  在开头我提到过这关概念有个名字,叫做“迪米特法则”

  一个方法的对象应该只引用该方法中的四种对象(注:可以简单称为"只与直接朋友通信"):

  1、它自己

  2、它的方法参数

  3、它创造或者实例化的任何对象

  4、有直接关联的对象

  

什么时候、怎么使用迪米特法则

  1、get的链

  最常用到的地方就是,如下

  value = object.getX().getY().getTheValue();

  (注:通过不停的get获得不同的对象,这样就与很多非直接朋友通信了,所以可以简单记为“减少点”,不过并不是“点多就是违反法则”。不过有篇文章介绍了,请参考The Law of Demeter Is Not A Dot Counting Exercise

)

  2、很多临时对象

结论

  我希望这篇论文能带给你一些新的东西。或许这些几乎就像常识一样普通。如果真的是这样,那很好。但是,理解它,给它一个统一的命名,然后人们可以使用它相互交流也是很好的。

原文请参考

  http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/paper-boy/demeter.pdf

转载于:https://www.cnblogs.com/junyuhuang/p/5630539.html

报童、钱包和迪米特法则(设计模式迪米特原则经典论文翻译)相关推荐

  1. 迪米特法则(设计模式5)

    迪米特法则: 迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说 ...

  2. 2016-12-28 迪米特法则+依赖倒转原则+里氏替换原则

    依赖倒转原则 依赖倒转原则,也翻译成依赖倒置原则,抽象不应该依赖细节,细节应该依赖于抽象,要针对接口编程,而不是对实现编程.如电脑中无论主板.CPU.内存.硬盘都是针对接口设计的,PC电脑硬件的发展, ...

  3. 面向对象软件设计原则【JAVA】(开闭原则、里氏代换、依赖倒转、接口隔离、迪米特法则、合成复用原则)

    软件设计原则[JAVA](开闭原则.里氏代换.依赖倒转.接口隔离.迪米特法则.合成复用原则) 1.开闭原则 2.里氏代换原则 3.依赖倒转原则 4.接口隔离原则 5.迪米特法则 6.合成复用原则 1. ...

  4. 迪米特法则(最少知道原则)

    10.3.5  迪米特法则(最少知道原则)(Demeter Principle) 迪米特法则(Law of Demeter)又叫最少知道原则(Least Knowledge Principle),19 ...

  5. 开闭原则、迪米特法则、合成复用原则

    开闭原则 1,一个软件实体如类,模块和函数应该对外扩展开放,对修改关闭,用抽象构建框架,用实现扩展细节 2.当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化 ...

  6. 迪米特法则 php,迪米特法则(The Law of Demeter) -解道Jdon

    迪米特法则 父母都会教育孩子们,不要和陌生人讲话,如果有陌生人试图和他们讲话,必须告诉爸爸妈妈,这是因为孩子们还不成熟,会相信一切成人告诉他们的事情,我们这样做是为了包含他们. 在面向对象编程中,我们 ...

  7. 【实验】软件设计原则,迪米特法则与开闭原则

    (一)实验原理 1.迪米特法则:不要和"陌生人"说话.或只与你的直接朋友通信. 我们称出现成员变量.方法参数.方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友. ...

  8. 迪米特法则(最少知识原则)

    定义 如果两个类不必彼此直接通信,那么这两个类就不应该发生直接的相互作用.如果一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个应用. 迪米特法则强调:在类的结构设计上,每一个类都应该尽量 ...

  9. 迪米特法则原理(最少知道原则)

    定义:是指一个对象类对于其他对象类来说,知道的越少越好.也就是说两个类之间不要有过多的耦合关系,保持最少关联性. 经典语录:只和朋友通信,不合陌生人说话. 也就是说有内在关联的类要内聚,没有直接关系的 ...

最新文章

  1. [js]uploadify结合jqueryUI弹出框上传,js中的冒出的bug,又被ie坑了
  2. TOML-to-Go : 帮你快速生成 Go 结构体
  3. iphone开发证书 纠结许久
  4. SDN/NFV运营商商业化部署
  5. 云鲸扫拖一体机器人说明书_云鲸扫拖一体机器人开箱测评。拖地机器人的天花板是什么样的?...
  6. NFS服务的配置过程
  7. 学习逆向知识之用于游戏外挂的实现.第二讲,快速寻找植物大战僵尸阳光基址.以及动态基址跟静态基址的区别...
  8. 【华为】对标谷歌Dropout专利,华为开源自研算法Disout,多项任务表现更佳
  9. netty冲突 play sbt_播放Cassandra Netty Server空指针异常-问答-阿里云开发者社区-阿里云...
  10. java面试题笔试常见选择题大全含答案
  11. 用豆瓣 API 爬《计算机科学丛书》示例
  12. LabVIEW编程LabVIEW开发 常用运动控制器比较
  13. 医院子母钟系统-YZ-9200
  14. 常见低压电器原理及电气符号(接触器、继电器、熔断器、断路器)基本原理及电气间隙与爬电距离
  15. K8S 三种探针 readinessProbe、livenessProbe和startupProbe
  16. Coursera 申请助学金流程和材料
  17. 智能客服 | 5款绝佳客户服务聊天机器人推荐
  18. [Usaco2010 Dec]Treasure Chest 藏宝箱
  19. JAVA之旅(三十五)——完结篇,终于把JAVA写完了,真感概呐!
  20. Oracle数据库条件筛选函数decode,NVL

热门文章

  1. 帮派红包 概率_电子游戏如何教我关于连锁帮派
  2. 设备设施管理内容有哪些?
  3. STM32 HAL 库0.96寸oledSSD1306 驱动
  4. 程序崩溃APPcrash的问题
  5. springboot 进阶
  6. java在浏览器闪退_浏览器连续闪退,作者来看看错误日志
  7. 「镁客·请讲」禾赛科技李一帆:定位激光雷达整体方案解决商,填补国内市场空白...
  8. vue2.0,vue3.0 v-model数据双向绑定
  9. 图像采集卡的选择和主要参数
  10. 教你用 python 画圣诞树