面向对象的7个设计原则->开车理解->贴近生活

点点圈 提交于 2019-12-03 14:02:22

  设计模式在我们的开发中是不可或缺的一部分,很多人会说,我没用那些设计模式啊,我也开发的挺好的,其实不然,我们在开发中都用到了这些设计模式,只不过我们并没有在意这些,今天我就用开车的方法来解释一下我们的7个设计原则。

简述

  面向对象的设计原则有七个,包括:开闭原则、单一职责原则、里氏替换原则、迪米特原则(最少知道原则)、接口分离原则、依赖倒置原则、组合/聚合复用原则。

1>开闭原则:

  在面向对象编程领域中,开闭原则规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查,单元测试以及诸如此类的用以确保产品使用质量的过程。遵循这种原则的代码在扩展时并不发生改变,因此无需上述的过程。摘自某度百科。

  上述那段话我是没看懂什么意思(我也没仔细的去看),开闭原则一句话来解释就是对扩展开放,对修改关闭。

  我们来举几个生活的栗子,小张开了一个饭店,湘菜做的很棒,顾客也越来越多了,也出现了在吃饭时间排队等候的现象,小张这时意识到我们应该扩张一下我们的饭店的规模了,于是把相邻的门店也一并租了下来,有人建议小张,你既然扩张了饭店的规模建议你去做一些别的事(严重不符合开闭原则),但是小张坚持还是做湘菜(符合开闭原则),也就是说小张你是在于原有的基础之上做了规模的扩张,而没有改变饭店原有特色菜的本质,这就是一个开闭原则的栗子。

  再比如,小张去洗浴中心or足疗保健or洗头房,我们可以点一些***的服务,我们也可以提出一些别的要求,比如花式开心,不管你提什么要求,也离不开,你想做的那些事的本质,不可能有人要求洗头小妹给你修脚吧。。。这里就是我们的可以提出对于***服务的扩展花样,但是不会修改原有***服务的本质。这也就是我们的开闭原则。

  从代码角度来说,就是无论我们如何去扩展类的方法和属性,也不要修改类本质的方法和属性,只扩展不修改现有,也禁止修改原有的属性。开闭原则是下面那些原则的总纲,切记很重要。


 2>单一职责原则:

  单一职责原则(SRP:Single responsibility principle)又称单一功能原则,面向对象五个基本原则(SOLID)之一。它规定一个类应该只有一个发生变化的原因。该原则由罗伯特·C·马丁(Robert C. Martin)于《敏捷软件开发:原则、模式和实践》一书中给出的。马丁表示此原则是基于汤姆·狄马克(Tom DeMarco)和Meilir Page-Jones的著作中的内聚性原则发展出的。摘自某度百科。

  单一职责,这个应该很好理解的,只做一件事,做好一件事就够了,生活中我们也常常会说,做好一件事不难,难的是一辈子只做这一件事。职责原则一句话来解释就是请做好自己的事。

  在生活中栗子有很多的,还是我们的小张开饭店的栗子,上面说了小张的饭店开的很红火,生意很好,之所以生意会好,是他一直坚持做他的特色菜,很多年了味道一直没有变过,还是那种熟悉的家乡味,有人建议他把特色菜的技术融入到烧烤,烤肉上去,小张摇摇头说,我们这是湘菜馆,不是烤肉店,我能一直做好我现在的特色菜就够了。这就是我们职责单一原则,两耳不闻别的事,单一只做一件事。

  再比如,小张又来足疗保健了,不耽误时间了,直接上楼吧,“来啊,服务员,来盘鱼香肉丝”。😂说完这句话,我怕老板娘会打死你。也就是说我们的职责是单一,来足疗店了,一楼洗脚的,二楼,***服务的。你来我这点鱼香肉丝...明显这很不符合常理啊。

  我们代码也应该是如此的,我们建立了一个Member类,主要是用来增删改查会员信息的,你现在写了一个积分新增的方法,你觉得合适吗?为了我们的代码的整洁,为了我们下次能找到积分新增的方法,你别把积分新增写Member类里好吗?😂我清晰的记得我们一个类干完一个项目的事....

 


 3>里氏替换原则:

   里氏替换原则,OCP作为OO的高层原则,主张使用“抽象(Abstraction)”和“多态(Polymorphism)”将设计中的静态结构改为动态结构,维持设计的封闭性。“抽象”是语言提供的功能。“多态”由继承语义实现。摘自某度百科。

   就是我们在继承的时候,子类的实现不要更改父类的方法,我们可以重写但是别改原来的方法。一句话说,你爱的事别人不一定爱。

   快要到中午吃饭的时间了,小张的饭店陆陆续续来了很多客人,有一桌客人点菜过程中发生了这样一件事,“哟,湘菜馆,我们点一个湘西外婆菜吧,好久没吃了”,“算了吧,我们上次去的那个小赵湘菜馆,没有湘西外婆菜,他这...也应该没有”,说到这我们可以看到这个人的思想是错误的,说到代码里就是,湘菜馆是一个父类,小赵湘菜馆和小张湘菜馆是子类,不能因为小赵湘菜馆没有湘西外婆菜,你就把所有的湘菜馆(父类)至为没有湘西外婆菜吧。

  忙完了中午,小张的腰包也变得鼓鼓的了,走起,足疗,上楼,关门..."服务员,来个可以沙漠风暴的。",“对不起先生,我们这没有沙漠风暴”,“算了,我换一家店吧”。到了第二家店,上楼,关门,“服务员,你家没有沙漠风暴吧~!”,“先生,我家各个可以沙漠风暴,不能因为一家店没有,你就说所有店都没有啊,您说是吧”。

  到我们实际代码上,比如我们建立了一个鸟类,属性是有羽毛,会飞等等,但是企鹅继承了我们的类,企鹅并不会飞,但我们并不能修改掉去说,所有的鸟类都不能飞,毕竟会飞鸟类还是大多数。

 4>迪米特原则:

  迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),就是说一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。英文简写为: LoD。摘自某度百科。

  感觉这个某度百科写的很容易理解,也就是我们的告诉你的,你知道,不告诉你的,你也别去问,一句话来说就是,知道太多对你没好处。

  小张的饭店今天来了一大桌子的客人,据说是县里的老板宴请客户吃饭,“服务员点菜,来个剁椒鱼头....”,“好的,马上给您下单,请问您叫什么名字,您家住在哪里?家里几口人”...你有病吧,我就来吃个饭,你至于问我那么多事情吗?我们可想而知,可能服务员快要挨打了,也很不符合常理的,我们只需要知道客人要吃什么就可以了,别的不需要知道,也没有必要知道。

  小张的身体素质还是很不错的,被打以后,没到三天就出院了,回家的路上,唉~!巧了路过一个足疗店,走起。上楼,关门,start...."小丽,技术还算不错的嘛?干几年了?这玩意赚钱吗?家里家口人啊?有男朋友吗?男朋友hi做什么的啊?",很明显,在足疗店出来转身又回医院了。

   

  从代码的角度来说,我们只写好我们当前的方法就可以了,别管其他方法内有什么参数,其他方法都做了什么。管好自己在说...


5>依赖倒置原则:

  依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。摘自某度百科。

  依赖倒置原则就是面向我们的接口编程,接口有什么,我们去做什么,而不是我们做了什么,再去加什么样的接口,一句话来说,根据接口写代码。

  比如小张的饭店,早起需要买菜供给今天一整天的菜品原材料,我们可以把菜品原材料比作接口,把做好的菜比作实现类,也就是说,我们每天买了什么菜品原材料,然后去做什么样的菜品,而不是因为你要做什么菜品,而去现买菜品的原材料的。

  小张忙里偷闲,又来到了足疗店,但是他忘记了他今天其实是想要去发廊的,理发等等事情要在发廊完成,进足疗店,上楼,“服务员,给我洗洗头...”显得好尴尬...足疗店,你要洗头...足疗店不可能根据你的需求,临时去加洗头的业务,也就是我们的小张,应该按照他去的足疗店的规矩来洗脚,而不是小张随心所欲的想要洗头就洗头。

  代码也是如此,我们都是先写好每一个接口,考虑好我们大概需要什么样的业务,然后去编写实现类。 


 6>接口分离原则:

  接口分离原则指在设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。即,一个类要给多个客户使用,那么可以为每个客户创建一个接口,然后这个类实现所有的接口;而不要只创建一个接口,其中包含所有客户类需要的方法,然后这个类实现这个接口。摘自某度百科。

  接口分离也很好理解的,和我们的职责单一其实差不多的,就是可以将一个总体的接口,按照一定的类别进行划分,换成一句话来说,就是一个小接口只做一类事情。

  小张的饭店依旧红火,他发现,后厨切菜的人员不够用了,现在他们招聘一个切墩的。于是去人才市场看一看,找到了一些合适的人员,有一个团队说,我们是系统化的,从洗菜,切菜,到炒菜,到洗碗,我们可以一条龙来完成的,你要一个切菜的人员,建议把我们全都雇佣过去,小张并不想这样,因为毕竟只是少了一个切菜的,不是全系统的后厨啊。团队看到他这番反应,赶紧又说,我们也可以只提供洗菜切菜服务的,您看满意吗?这也恰恰就是我们想要的,也就是有时候并不是全面才是更好的,我们应该尽可能将菜品处理,菜品的制作,器皿的清洗分开来进行组成团队。

  这次后厨可以忙的开了,小张下午没事又来到了足疗店,由于不是休息日,店里的顾客并不是很多,很多小妹都闲着,不多说,先上楼,来了服务员介绍,这个是小花,这个是大美,他们是一个姐妹组合,但小张完成无法接受姐妹花组合,只好点了小花一个人,如果说我们的姐妹花组合是无法分开的,小张可能就要受累了。

  说到代码里,我们的一个接口内可能有好几十个方法,有新增人员的,有修改人员的,有编辑库存的等等,这里我们只是想对人员进行操作,我们实现了这个接口,即使你写空方法,也要将我们的全部方法实现一次,累不累,所以说我们应该将我们的接口合理的切分,弄成人员操作接口和库存操作的接口等等。


 7>组合/聚合复用原则:

  某度百科没找到,这里强调一个事啊,有人会说没有什么7大设计原则,本来是6个的,没有这个组合/聚合复用原则,其实不然,有很多OOP的原则,凑在一起,可能是6大,可能是7大,也可能“5大”,例如比较著名的SOLID,就是5个原则的缩写。其实说到底,就是要减小代码的重复和冗余,使其便于理解和维护。

  组合/聚合复用原则尽量使用对象组合,而不是继承来达到复用的目的。

  还是小张的饭店,这次呢小张引进了新菜品,红烧肉,卖的很好,很红火,经常是肉不够卖的,小张的爸爸是一名市场卖肉的,小张每天都是去他爸爸的摊位购买肉,看到了生意如此的红火,红烧肉尝尝脱销,有人就建议说,你在你店里为你爸爸弄一个卖肉的摊位算了,反正你红烧肉每天都不够卖,为何不将摊位“继承”到你的店里呢。小张完全没有心动,正常人不会这么做的,我一个饭店,卖毛线生肉呢,我红火的是红烧肉,不是生肉。也就是我们的组合/聚合复用原则,我们需要生肉作为原材料,但是并属于我们生意的范畴,我们没有必要把整个肉店都弄来是吧。

  小张最后一次开饭店了,因为这是最后一个原则了,为了庆祝小张去了足疗店,走向足疗一条街,选门店,开门,话不多说,直接上二楼...但精油没有了,你说你是让服务员下楼买一瓶好呢?还是把精油专柜搬上来,让精油售卖员一个个给你介绍好呢?有人说介绍的比较全面啊,那面我接下来的事,难道你也让精油售卖员眼睁睁的看着你吗?说回来没有必要的事,不用继承下来所有的吧。

  说到代码里,我们的数据访问层(持久层),我们内部只要一个DB的连接就可以了,而并不需要继承我们的DB连接类啊,直接New一个全局的就可以了吧,并没有必要去全部拿过来。

总结:

  其实我们的那几个原则我们的代码中都会遇到,就是我们不太注意的问题。我们来回顾一下7个原则。

  开闭原则:扩展开,修改关。

  单一职责原则:只做一件事。

  里氏替换原则:别动你觉得没用的属性,你觉得毕竟是你觉得。

  迪米特原则(最少知道原则):知道的太多对你没好处。

  接口分离原则:大变小,小专一。

  依赖倒置原则:根据接口写代码,没事别自创。

  组合/聚合复用原则:用多少拿多少。

开车的方式可能有一些人不喜欢,还请见谅

最进弄了一个公众号,小菜技术,欢迎大家的加入

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!