关系经济人类预测化学自然
中准网
自然科学
知识物理
化学生物
地理解释
预测理解
本质社会
人类现象
行为研究
经济政治
心理结构
关系指导
人文遗产

学会这6个设计原则中,你也能写出优雅的代码

9月13日 终离去投稿
  前言
  一个优雅的代码,犹如亭亭玉立的美女,让人赏心悦目。而糟糕的代码,却犹如屎山,让人避而远之。如何写出优雅的代码,应该都要理解并熟悉应用这6个设计原则:开闭原则、单一职责原则、接口隔离原则、迪米特法则、里氏替换原则、依赖倒置原则。本文呢,将通过代码例子,让大家轻松理解这6个代码设计原则。1。开闭原则
  开闭原则,即对扩展开放,对修改关闭。
  对于扩展和修改,我们怎么去理解它呢?扩展开放表示,未来业务需求是变化万千,代码应该保持灵活的应变能力。修改关闭表示不允许在原来类修改,保持稳定性。
  因为日常需求是不断迭代更新的,所以我们经常需要在原来的代码中修改。如果代码设计得不好,扩展性不强,每次需求迭代,都要在原来代码中修改,很可能会引入bug。因此,我们的代码应该遵循开闭原则,也就是对扩展开放,对修改关闭。
  为了方便大家理解开闭原则,我们来看个例子:假设有这样的业务场景,大数据系统把文件推送过来,根据不同类型采取不同的解析方式。多数的小伙伴就会写出以下的代码:if(typeA){按照A格式解析}elseif(typeB){按B格式解析}else{按照默认格式解析}复制代码
  这段代码有什么问题呢?如果分支变多,这里的代码就会变得臃肿,难以维护,可读性低。如果你需要接入一种新的解析类型,那只能在原有代码上修改。
  显然,增加、删除某个逻辑,都需要修改到原来类的代码,这就违反了开闭原则了。为了解决这个问题,我们可以使用策略模式去优化它。
  你可以先声明一个文件解析的接口,如下:publicinterfaceIFileStrategy{属于哪种文件解析类型,A或者BFileTypeResolveEnumgainFileType();封装的公用算法(具体的解析方法)voidresolve(Objectparam);}复制代码
  然后实现不同策略的解析文件,如类型A解析:ComponentpublicclassAFileResolveimplementsIFileStrategy{OverridepublicFileTypeResolveEnumgainFileType(){returnFileTypeResolveEnum。FileARESOLVE;}Overridepublicvoidresolve(Objectobjectparam){logger。info(A类型解析文件,参数:{},objectparam);A类型解析具体逻辑}}复制代码
  如果未来需求变更的话,比如增加、删除某个逻辑,不会再修改到原来的类啦,只需要修改对应的文件解析类型的类即可。
  对于如何使用设计模式,大家有兴趣的话,可以看我以前的这篇文章哈:实战!工作中常用到哪些设计模式2。单一职责原则
  单一职责原则:一个类或者一个接口,最好只负责一项职责。比如一个类C违反单一原则,它负责两个职责P1和P2。当职责P1需要修改时,就会改动到类C,这就可能导致原本正常的P2也受影响。
  如何更好理解呢?比如你实现一个图书管理系统,一个类既有图书的增删改查,又有读者的增删改查,你就可以认为这个类违反了单一原则。因为这个类涉及了不同的功能职责点,你可以把这个拆分。
  以上图书管理系统这个例子,违反单一原则,按业务拆分。这比较好理解,但是有时候,一个类并不是那么好区分。这时候大家可以看这个标准,来判断功能职责是否单一:类中的私有方法过多你很难给类起一个合适的名字类中的代码行数、函数或者属性过多类中大量的方法都是集中操作类中的某几个属性类依赖的其他类过多,或者依赖类的其他类过多
  比如,你写了一个方法,这个方法包括了日期处理和借还书的业务操作,你就可以把日期处理抽到私有方法。再然后,如果你发现,很多私有方法,都是类似的日期处理,你就可以把这个日期处理方法抽成一个工具类。
  日常开发中,单一原则的思想都有体现的。比如微服务拆分,也是这个原则的思想。3。接口隔离原则
  接口隔离原则:接口的调用者或者使用者,不应该强迫依赖它不需要的接口。它要求建立单一的接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少,让接口中只包含客户(调用者)感兴趣的方法。即一个类对另一个类的依赖应该建立在最小的接口上。
  比如类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说,都不是最小接口,则类B和类D必须去实现他们不需要的方法。如下图:
  这个图表达的意思是:类A依赖接口I中的method1、method2,类B是对类A依赖的实现。类C依赖接口I中的method1、method3,类D是对类C依赖的实现。对于实现类B和D,它们都存在用不到的方法,但是因为实现了接口I,所以必须要实现这些用不到的方法。
  可以看下以下代码:publicinterfaceI{voidmethod1();voidmethod2();voidmethod3();}ServicepublicclassA{Resource(nameB)privateIi;publicvoiddepend1(){i。method1();}publicvoiddepend2(){i。method2();}}Service(B)publicclassBimplementsI{Overridepublicvoidmethod1(){System。out。println(类B实现接口I的方法1);}Overridepublicvoidmethod2(){System。out。println(类B实现接口I的方法2);}没用到这个方法,但是也要默认实现,因为I有这个接口方法Overridepublicvoidmethod3(){}}ServicepublicclassC{Resource(nameD)privateIi;publicvoiddepend1(Ii){i。method1();}publicvoiddepend3(Ii){i。method3();}}Service(D)publicclassDimplementsI{Overridepublicvoidmethod1(){System。out。println(类D实现接口I的方法1);}没用到这个方法,但是也要默认实现,因为I有这个接口方法Overridepublicvoidmethod2(){}Overridepublicvoidmethod3(){System。out。println(类D实现接口I的方法3);}}复制代码
  大家可以发现,如果接口过于臃肿,只要接口中出现的方法,不管对依赖于它的类有没有用到,实现类都必须去实现这些方法。实现类B没用到method3,它也要有个默认实现。实现类D没用到method2,它也要有个默认实现。
  显然,这不是一个好的设计,违反了接口隔离原则。我们可以对接口I进行拆分。拆分后的设计如图2所示:
  接口是不是分得越细越好呢?并不是。日常开发中,采用接口隔离原则对接口进行约束时,要注意以下几点:接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。运用接口隔离原则,一定要适度,接口设计得过大或过小都不好。设计接口的时候,只有多花些时间去思考和筹划,才能准确地实践这一原则。4。迪米特法则
  定义:又叫最少知道原则。一个类对于其他类知道得越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友谈心,不和陌生人说话。它的核心思想就是,尽量降低类与类之间的耦合,尽最大能力减小代码修改带来的对原有的系统的影响。
  比如一个生活例子:你对你的对象肯定了解得很多,但是如果你对别人的对象也了解很多,你的对象要是知道,那就要出大事了。
  我们来看下一个违反迪米特法则的例子,业务场景是这样的:一个学校,要求打印出所有师生的ID。学生classStudent{privateSpublicvoidsetId(Stringid){this。}publicStringgetId(){}}老师classTeacher{privateSpublicvoidsetId(Stringid){this。}publicStringgetId(){}}管理者(班长)publicclassMonitor{所有学生publicListStudentgetAllStudent(){ListStudentlistnewArrayListStudent();for(inti0;i100;i){StudentstudentnewStudent();为每个学生分配个IDstudent。setId(学生Id:i);list。add(student);}}}校长publicclassPrincipal{所有教师publicListTeachergetAllTeacher(){ListTeacherlistnewArrayListTeacher();for(inti0;i30;i){TeacherempnewTeacher();为全校老师按顺序分配一个IDemp。setId(老师编号i);list。add(emp);}}所有师生publicvoidprintAllTeacherAndStudent(ClassMonitorclassMonitor){ListStudentlist1classMonitor。getAllStudent();for(Students:list1){System。out。println(s。getId());}ListTeacherlist2this。getAllTeacher();for(Teacherteacher:list2){System。out。println(teacher。getId());}}}复制代码
  这块代码。问题出在类Principal中,根据迪米特法则,只能与直接的朋友发生通信,而Student类并不是Principal类的直接朋友(以局部变量出现的耦合不属于直接朋友),从逻辑上讲校长Principal只与管理者Monitor耦合就行了,可以让Principal继承类Monitor,重写一个printMember的方法。优化后的代码如下:publicclassMonitor{publicListStudentgetAllStudent(){ListStudentlistnewArrayListStudent();for(inti0;i100;i){StudentstudentnewStudent();为每个学生分配个IDstudent。setId(学生Id:i);list。add(student);}}publicvoidprintMember(){ListStudentlistthis。getAllStudent();for(Studentstudent:list){System。out。println(student。getId());}}}publicclassPrincipalextendsMonitor{publicListTeachergetAllTeacher(){ListTeacherlistnewArrayListTeacher();for(inti0;i30;i){TeacherempnewTeacher();为全校老师按顺序分配一个IDemp。setId(老师编号i);list。add(emp);}}publicvoidprintMember(){super。printMember();for(Teacherteacher:this。getAllTeacher()){System。out。println(teacher。getId());}}}复制代码5。里氏替换原则
  里氏替换原则:
  如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。
  一句话来描述就是:只要有父类出现的地方,都可以用子类来替代,而且不会出现任何错误和异常。更通俗点讲,就是子类可以扩展父类的功能,但是不能改变父类原有的功能。
  其实,对里氏替换原则的定义可以总结如下:子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法子类中可以增加自己特有的方法当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松当子类的方法实现父类的方法时(重写重载或实现抽象方法),方法的后置条件(即方法的的输出返回值)要比父类的方法更严格或相等
  我们来看个例子:publicclassCache{publicvoidset(Stringkey,Stringvalue){}}publicclassRedisCacheextendsCache{publicvoidset(Stringkey,Stringvalue){}}复制代码
  这里例子是没有违反里氏替换原则的,任何父类、父接口出现的地方子类都可以出现。如果给RedisCache加上参数校验,如下:publicclassCache{publicvoidset(Stringkey,Stringvalue){}}publicclassRedisCacheextendsCache{publicvoidset(Stringkey,Stringvalue){if(keynullkey。length()10key。length()100){System。out。println(key的长度不符合要求);thrownewIllegalArgumentException();}}}复制代码
  这就违反了里氏替换原则了,因为子类方法增加了加了参数校验,抛出了异常,虽然子类仍然可以来替换父类。6。依赖倒置原则
  依赖倒置原则定义:
  高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。它的核心思想是:要面向接口编程,而不要面向实现编程。
  依赖倒置原则可以降低类间的耦合性、提高系统的稳定性、减少并行开发引起的风险、提高代码的可读性和可维护性。要满足依赖倒置原则,我们需要在项目中满足这个规则:每个类尽量提供接口或抽象类,或者两者都具备。变量的声明类型尽量是接口或者是抽象类。任何类都不应该从具体类派生。使用继承时尽量遵循里氏替换原则。
  我们来看一段违反依赖倒置原则的代码,业务需求是:顾客从淘宝购物。代码如下:classCustomer{publicvoidshopping(TaoBaoShopshop){购物System。out。println(shop。buy());}}复制代码
  以上代码是存在问题的,如果未来产品变更需求,改为顾客从京东上购物,就需要把代码修改为:classCustomer{publicvoidshopping(JingDongShopshop){购物System。out。println(shop。buy());}}复制代码
  如果产品又变更为从天猫购物呢?那有得修改代码了,显然这违反了开闭原则。顾客类设计时,同具体的购物平台类绑定了,这违背了依赖倒置原则。可以设计一个shop接口,不同购物平台(如淘宝、京东)实现于这个接口,即修改顾客类面向该接口编程,就可以解决这个问题了。代码如下:classCustomer{publicvoidshopping(Shopshop){购物System。out。println(shop。buy());}}interfaceShop{Stringbuy();}ClassTaoBaoShopimplementsShop{publicStringbuy(){return从淘宝购物;}}ClassJingDongShopimplementsShop{publicStringbuy(){return从京东购物;}}
  原文:https:juejin。cnpost7156624841422929933
投诉 评论 转载

被他们治愈了人间烟火里留一个位置给自己心中的热爱头条创作挑战赛我们的生活总在奔波忙碌,抱怨生活艰难,生活不易,看到他们在人间烟火里留一个位置给自己心中的热爱,被他们热烈喜欢生活的态度治愈了。外卖小哥啊仁,也是爱弹……秋分养生,这些秘诀快收藏分,是二十四节气中的第16个节气,它的到来预示着秋意渐浓,我国大部分地区已经进入凉爽的秋季。重庆两江二院(中医院)疼痛康复科专家提醒大家,秋分作为昼夜时间相等的节气,人们……爱发体育斯科尔斯谈加纳乔他是个天才在左右两侧都有进攻能力斯科尔斯谈加纳乔他是个天才在左右两侧都有进攻能力在今日凌晨结束的欧联杯AiFA体育:世界杯五大联赛竞猜最后一轮小组赛中,曼联客场10击败皇家社会小组第二晋级欧联杯淘汰赛,……当自私达到一定程度,人性就变成了恶1人生两境界,知道与知足。最难的是读懂生活,却依然热爱生活,看穿所有,却依然向往美好。2利益越大的地方,人性就会越自私;当自私达到一定程度,人性就变成了恶。3说钱不……学会这6个设计原则中,你也能写出优雅的代码前言一个优雅的代码,犹如亭亭玉立的美女,让人赏心悦目。而糟糕的代码,却犹如屎山,让人避而远之。如何写出优雅的代码,应该都要理解并熟悉应用这6个设计原则:开闭原则、单一职责……人生,活的是心情,过的是心态时代的一粒灰,落在个人头上,就是一座山。疫情给我们生活带来的冲击,也不外乎是:身体不适、言行不当、情绪不稳、心态不安每个人都被裹挟着、被惊吓着,手忙脚乱地奔波忙碌着……国产新能源再发力,车长近5米,最高续航715km6。9秒破百前不久笔者上班乘坐网约车,看到一辆品牌为哪吒的车型,不由大感兴趣,多方了解到其是一款合众汽车推出的新能源车型,而该品牌也在今年7月推出了一款新的车型,哪吒S2022款,官方指导……百度首发时空数智中台,助力智能交通与智慧城市创新发展花朵财经11月11日,在成都举行的第十七届中国智能交通年会上,聚焦智能交通与智慧城市融合发展,百度首次发布时空数智中台,致力于挖掘地理信息的时空及大数据价值,服务智慧城市……圆周率已算到62。8万亿位,科学家对如此执着,到底是为什么综述圆形是世界上最常见的图形,比如水滴落的形状,太阳的轮廓,人类的瞳孔,生活中处处可见圆的形状,似乎整个宇宙都是由圆形构成的一般,对此,科学家们开始对圆进行研究,并认为其……成都这个古镇,太宝藏了解小编带着大家游玩古镇,最后一期,顺着河流我们走到了古街上,古街商业化不严重,客栈酒吧和餐厅,该有的都有,接下来让解小编来为你们介绍古镇的土特产和著名的美食吧。色香俱全的……音箱和功放的搭配问题一个超级难的问题对广大的发烧友来说,音箱和功放的搭配都是一个非常让人头痛的问题,尤其是对入门级的发烧友而言更是如此。很多烧友明明知道无源音箱搭配好了要远远胜过有源,但一样选择了有源,主要原因就……四川最美二十个景区推荐四川是中国旅游大省,巴蜀山水,钟灵毓秀,自古是人们向往的美丽富饶、安宁祥和、气象万千的梦中仙境,早有天府之国的雅号,而东方伊甸园的美称更使之别具浪漫情调。四川是旅游爱好者的天堂……
白冰穿露脐装的样子太可爱,夏天范很足,仿佛美回十八岁NBA球星中国行即将回归!殳海暗示安踏将签下某神秘球星翻版灵动岛?realmeNarzoN55发布,采用mini胶上海通过艰难的比赛,终于战胜对手,这是一场载入史册的经典比赛中超火热开启!反腐风暴持续发酵,名记中超老将月薪仅3万元这些好口碑的爽肤水,人气超高,口碑都特棒,巨好用,让肌肤更细通过2022年一季度的经济数据看中美的差距看了10份ESG报告,我们发现了这些门道TCLQ10GMiniLED电视新品发布王炸画质,新品首发价头皮瘙痒怎么办,教你摆脱头皮瘙痒比芯片封锁更可怕,美芯片专家多数是华人,国内半导体开始觉醒万物皆数
游仙词十首,并引其九什么咖啡好喝又减肥呢领克02限时优惠2000元欢迎试乘试驾来年造句用来年造句大全寻衅滋事罪主动自首怎么判?维护消费者权益的机构都有哪些呢?iPhone14值得涨价!前提得标配256GB内存,可国产旗阿尔奇简介难忘的一次冒险小学作文怎样将excel表格中的数据分类汇总一男子故意传染艾滋病还炫耀?老谣言台风红色预警(台风红色)

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找菏泽德阳山西湖州宝鸡上海茂名内江三亚信阳长春北海西安安徽黄石烟台沧州湛江肇庆鹤壁六安韶关成都钦州