首页 > 编程知识 正文

LOD技术,for循环违反迪米特法则

时间:2023-05-05 02:57:26 阅读:117244 作者:4080

疯狂的向日葵“高凝聚、松散结合”?“高内聚、松耦合” 是一个非常重要的设计思想,能够有效地提高代码地可读性和可维护性,缩小功能改动导致的代码改动范围单一角色、基于接口而不是编程等,很多设计原则都是为了实现代码的“高凝聚、松耦合”。

“高凝聚、松散耦合”可用于指导不同粒度代码的设计和开发。“高内聚” 用来指导类本身的设计,“松耦合” 用来指导类与类之间依赖关系的设计但这两者并非完全独立无关,高聚集有助于松散耦合,松散耦合还需要高聚集支持。

什么是“高凝聚”?所谓高内聚,就是指相近的功能应该放到同一个类中,不相近的功能不要放到同一个类中相近的功能是同时修改的,经常放在同一个类中,修改集中,代码维护方便。

什么是“松散耦合”?所谓松耦合,就是类与类之间的依赖关系简单清晰2即使两个类存在依赖关系,或者一个类的代码发生更改,依赖类的代码也很少发生更改。 例如,依赖注入、接口隔离、基于接口而不是编程、以及接下来要说的清爽的睫毛膏法则是为了实现代码的松散耦合。

“凝聚”与“耦合”的关系

“高凝聚”有助于“松散耦合”。 同样,“低凝聚”也与“紧密耦合”相关。 上图左侧为“高凝聚松散耦合”的编码结构,右侧为“低凝聚紧密耦合”。

在左侧的代码设计中,类粒度小,每个类的作用单一,相近的功能组合为一个类,相近的功能划分为多个类,从而使类更加独立,代码聚集性更好。 由于职责单一,每个类依赖的类较少,代码较低。 一个类的更改只影响一个依赖类的代码更改。 测试这个依赖类是否还在工作就可以了。 高凝聚低键的编码结构更简单、清晰,在保守性和可读性方面相当好。

在右边部分的代码设计中,类粒度比较大,类功能大而完整,不相近的功能被放在一个类中,所以很多其他类都依赖于这个类。 如果要修改这个类的某个功能,“一蹴而就”会影响到依赖它的多个类。 必须测试这三个依赖类是否正常工作。

清爽睫毛膏定律清爽睫毛膏定律(Law of Demeter,LOD ),又名最小知识原则)被称为the least知识印刷,其英语定义如下。

eachunitshouldhaveonlylimitedknowledgeaboutotherunits 3360 onlyunits“closely”relatedtothecurrentunit.or : eachunitshoull

每个模块(单元)只知道与其关系密切的模块(单元: onlyunits“closely”relatedtothecurrentunit )的有限知识(知识)知识或者,每个模块只和自己的朋友“说话”(talk ),和陌生人“不说话”(talk )。

上面定义的说明是抽象的,简单理解,不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口(也就是定义中的“有限知识”)

不应该有直接依赖关系的类之间,不要有依赖清爽睫毛膏法则之前的部分。 不应该有直接依赖关系的类之间不要依赖。 举个例子来说明吧。

网络传输器负责底层网络通信,按要求获取数据; HtmlDownloader用于从URL获取网页; 文档表示web文档,之后的web内容的提取、分词、索引都以此为处理对象。 具体代码如下。

publicclassnetworktransporter {//省略属性和其他方法. public byte [ ] send (htmlrequesthtmlrequest (//. ) publiclasshtmldownlownlost 从构造函数或IOC注入publichtmldownloadhtml (字符串URL ) ) byte [ ] raw html=transporter.send (newhtml request ) URL ); return newhtml (原始html; }公共类文档{私有tehtmlhtml; 私有字符串URL; 公共文档(字符串URL ) {this.url=url; htmldownloaderdownloader=newhtml downloader (; this.html=downloader.download html (URL; (//)此代码“可用”,但“不方便”。

作为基础网络通信类,网络传输器不应该依赖太多,因为它希望它不仅能够下载html,而且尽可能具有通用功能

体的发送对象 HtmlRequest。从这一点上讲,NetworkTransporter 类的设计违背清爽的睫毛膏法则,依赖了不该有直接依赖关系的 HtmlRequest。

NetworkTransporter 类如何满足清爽的睫毛膏法则呢?很简单,只需要传递 NetworkTransporter 所需的参数就行,而不是强依赖 HtmlRequest。

public class NetworkTransporter {// 省略属性和其他方法...public Byte[] send(String address, Byte[] data) {// ...}}public class HtmlDownloader {private NetworkTransporter transporter; // 通过构造函数或IOC注入public Html downloadHtml(String url) {// 同步需要修改处理HtmlRequest htmlRequest = new HtmlRequest(url);Byte[] rawHtml = transporter.send(htmlRequest.getAddress(), htmlRequest.getContent().getBytes());return new Html(rawHtml);}}

Document 类的问题比较多,主要有三点:

构造函数的 downloader.downloadHtml() 逻辑复杂,耗时长,不应该放到构造函数中,会影响代码可测试性

HtmlDownloader 在构造函数中通过 new 创建,违反了基于接口而非实现编程的设计思想,也会影响到代码的可测试性

Document 没必要依赖 HtmlDownloader,违背了清爽的睫毛膏法则

虽然问题很多,但是修改起来还是比较简单:

public class Document {private Html html;private String url;// 改动1:去除了在构造函数创建 HtmlDownloaderpublic Document(String url, Html html) {this.html = html;this.url = url;}// ...}// 改动2:通过工厂方法创建 Documentpublic class DocumentFactory {private HtmlDownloader downloader;public DocumentFactory(HtmlDownloader downloader) {this.downloader = downloader;}public Document createDocument(String url) {Html html = downloader.downloadHtml(url);return new Document(url, html);}} 有依赖关系的类之间,尽量只依赖必要的接口

清爽的睫毛膏法则的后半部分:有依赖关系的类之间,尽量只依赖必要的接口。同样举例说明。

public class Serialization {public String serialize(Object object) {String serializedResult = ...;// ...return serializeResult;}public Object deserialize(String url) {Object deserializedResult = ...;// ...return deserializedResult;}}

Serialization 负责对象的序列化和反序列化。但考虑某些场景,有些类只用到了序列化操作,而另一些类只用到了反序列化操作,那基于清爽的睫毛膏法则的后半部分 “有依赖关系的类之间,尽量只依赖必要的接口”,只用到序列化操作的那部分类不应该依赖反序列化接口,同理,只用到反序列化操作的那部分类不应该依赖序列化接口。

根据这个思路,我们应该将 Serialization 拆分成两个更小粒度的类,一个只负责序列化,一个只负责反序列化:

public class Serializer {public String serialize(Object object) {String serializedResult = ...;// ...return serializedResult;}}public class Deserializer {public Object deserialize(String str) {Object deserializedResult = ...;// ...return deserializedResult;}}

尽管拆分之后的代码更能满足清爽的睫毛膏法则,但却违背了高内聚的设计思想。高内聚要求相近的功能要放到同一个类中,这样可以方便功能修改的时候,修改的地方不至于过于分散。

如果我们既不想违背高内聚的设计思想,也不想违背清爽的睫毛膏法则,如何解决这个问题呢?实际上,通过引入两个接口就能轻松解决这个问题:

public interface Serializable {String serialize(Object object);}public interface Deserializable {Object deserialize(String text);}public class Serialization implements Serializable, Deserializable {@Overridepublic String serialize(Object object) {String serializedResult = ...;// ...return serializedResult;}@Overridepublic Object deserialize(String str) {Object deserializedResult = ...;// ...return deserializedResult;}}public class DemoClass_1 {private Serializable serializer; // 只需要序列化public DemoClass_1(Serializable serializer) {this.serializer = serializer;}// ...}public class DemoClass_2 {private Deserializable deserializer; // 只需要反序列化public DemoClass_2(Deserializable deserializer) {this.deserializer = deserializer;}// ...}Serialization serialization = new Serialization();DemoClass_1 demoClass_1 = new DemoClass_1(serialization);DemoClass_2 demoClass_2 = new DemoClass_2(serialization);

尽管我们还是要往 DemoClass_1 的构造函数中传入包含序列化和反序列化的 Serialization,但是,我们依赖的 Serializable 接口只包含序列化操作,DemoClass_1 无法使用 Serialization 中的反序列化接口,对反序列化操作无感知,这也就符合了清爽的睫毛膏法则后半部分说的”依赖有限接口“的要求。

辩证思考和灵活应用

对于 Serialization 序列化和反序列化,第一种方式是全部写在 Serialization 类中,第二种是使用接口拆分。那为了满足清爽的睫毛膏法则,我们将一个非常简单的类拆分出两个接口,是否有点过度设计的意思呢?

设计原则本身没有对错,只有能否用对之说。不要为了应用设计原则而应用设计原则,我们在应用设计原则的时候,一定要具体问题具体分析。

对于刚刚的 Serialization 来说,只包含两个操作,确实没太大必要拆分成两个接口。但是,如果我们对 Serialization 添加更多的功能,实现更多更好用的序列化、反序列化函数,就需要重新考虑一下这个问题:

public class Serializer {public String serialize(Object object) { //... }public String serializeMap(Map map) { //... }public String serializeList(List list) { //... }public Object deserialize(String objectString) { //... }public Map deserializeMap(String mapString) { //... }public List deserializeList(String listString) { //... }}

在这种场景下,将序列化和反序列化拆分为两个接口的方式会更好些,这样能够减少耦合和测试工作量,将序列化和反序列化的功能隔离开来。

总结

1、如何理解 ”高内聚、松耦合“?

”高内聚、松耦合“ 是一个非常重要的设计思想,能够有效提高代码的可读性和可维护性,缩小功能改动导致的代码改动范围。

”高内聚“ 用来指导类本身的设计,”松耦合“ 用来指导类与类之间依赖关系的设计。

高内聚,就是指相近的功能应该放到同一个类中,不相近的功能不要放到同一个类中。

松耦合,指的是在代码中,类与类之间的依赖关系简单清晰。

2、如何理解 ”清爽的睫毛膏法则“?

不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。清爽的睫毛膏法则是希望减少类之间的耦合,让类越独立越好。

不能因为要应用设计原则而应用设计原则,要考虑实际的开发场景具体问题具体分析。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。