范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

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

  前言
  一个优雅的代码,犹如亭亭玉立的美女,让人赏心悦目。而糟糕的代码,却犹如屎山,让人避而远之。如何写出优雅的代码,应该都要理解并熟悉应用这6个设计原则:开闭原则、单一职责原则、接口隔离原则 、迪米特法则、里氏替换原则、依赖倒置原则。本文呢,将通过代码例子,让大家轻松理解这6个代码设计原则。1. 开闭原则
  开闭原则,即对扩展开放,对修改关闭。
  对于扩展和修改,我们怎么去理解它呢?扩展开放表示,未来业务需求是变化万千,代码应该保持灵活的应变能力。修改关闭表示不允许在原来类修改,保持稳定性。
  因为日常需求是不断迭代更新的,所以我们经常需要在原来的代码中修改。如果代码设计得不好,扩展性不强,每次需求迭代,都要在原来代码中修改,很可能会引入bug。因此,我们的代码应该遵循开闭原则,也就是对扩展开放,对修改关闭。
  为了方便大家理解开闭原则,我们来看个例子:假设有这样的业务场景,大数据系统把文件推送过来,根据不同类型采取不同的解析方式。多数的小伙伴就会写出以下的代码:if(type=="A"){    //按照A格式解析   }else if(type=="B"){     //按B格式解析 }else{     //按照默认格式解析 } 复制代码
  这段代码有什么问题呢?如果分支变多,这里的代码就会变得臃肿,难以维护,可读性低。如果你需要接入一种新的解析类型,那只能在原有代码上修改。
  显然,增加、删除某个逻辑,都需要修改到原来类的代码,这就违反了开闭原则了。为了解决这个问题,我们可以使用策略模式去优化它。
  你可以先声明一个文件解析的接口,如下:public interface IFileStrategy {          //属于哪种文件解析类型,A或者B     FileTypeResolveEnum gainFileType();          //封装的公用算法(具体的解析方法)     void resolve(Object param); } 复制代码
  然后实现不同策略的解析文件,如类型A解析:@Component public class AFileResolve implements IFileStrategy {          @Override     public FileTypeResolveEnum gainFileType() {         return FileTypeResolveEnum.File_A_RESOLVE;     }      @Override     public void resolve(Object objectparam) {       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,所以必须要实现这些用不到的方法。
  可以看下以下代码:public interface I {      void method1();      void method2();      void method3(); }  @Service public class A {      @Resource(name="B")     private I i;      public void depend1() {         i.method1();     }      public void depend2(){         i.method2();     }  }  @Service("B") public class B implements I {      @Override     public void method1() {         System.out.println("类B实现接口I的方法1");     }      @Override     public void method2() {         System.out.println("类B实现接口I的方法2");     }      //没用到这个方法,但是也要默认实现,因为I有这个接口方法     @Override     public void method3() {      } }  @Service public class C {      @Resource(name="D")     private I i;      public void depend1(I i){         i.method1();     }      public void depend3(I i){         i.method3();     }  }  @Service("D") public class D implements I {      @Override     public void method1() {         System.out.println("类D实现接口I的方法1");     }      //没用到这个方法,但是也要默认实现,因为I有这个接口方法     @Override     public void method2() {      }      @Override     public void method3() {         System.out.println("类D实现接口I的方法3");     } } 复制代码
  大家可以发现,如果接口过于臃肿,只要接口中出现的方法,不管对依赖于它的类有没有用到,实现类都必须去实现这些方法。实现类B没用到method3,它也要有个默认实现。实现类D没用到method2,它也要有个默认实现。
  显然,这不是一个好的设计,违反了接口隔离原则。我们可以对接口I进行拆分。拆分后的设计如图2所示:
  接口是不是分得越细越好呢?并不是。日常开发中,采用接口隔离原则对接口进行约束时,要注意以下几点:接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。 运用接口隔离原则,一定要适度,接口设计得过大或过小都不好。设计接口的时候,只有多花些时间去思考和筹划,才能准确地实践这一原则。4. 迪米特法则
  定义:又叫最少知道原则。一个类对于其他类知道得越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友谈心,不和陌生人说话。它的核心思想就是,尽量降低类与类之间的耦合,尽最大能力减小代码修改带来的对原有的系统的影响。
  比如一个生活例子:你对你的对象肯定了解得很多,但是如果你对别人的对象也了解很多,你的对象要是知道,那就要出大事了。
  我们来看下一个违反迪米特法则的例子,业务场景是这样的:一个学校,要求打印出所有师生的ID。//学生   class Student{       private String id;       public void setId(String id){           this.id = id;       }       public String getId(){           return id;       }   }    //老师   class Teacher{       private String id;       public void setId(String id){           this.id = id;       }       public String getId(){           return id;       }   }    //管理者(班长) public class Monitor {       //所有学生     public List getAllStudent(){         List list = new ArrayList();         for(int i=0; i<100; i++){             Student student = new Student();             //为每个学生分配个ID             student.setId("学生Id:"+i);             list.add(student);         }         return list;     }  }  //校长 public class Principal {      //所有教师     public List getAllTeacher(){         List list = new ArrayList();         for(int i=0; i<30; i++){             Teacher emp = new Teacher();             //为全校老师按顺序分配一个ID             emp.setId("老师编号"+i);             list.add(emp);         }         return list;     }      //所有师生     public void printAllTeacherAndStudent(ClassMonitor classMonitor) {          List list1 = classMonitor.getAllStudent();         for (Student s : list1) {             System.out.println(s.getId());         }          List list2 = this.getAllTeacher();         for (Teacher teacher : list2) {             System.out.println(teacher.getId());         }     } }  复制代码
  这块代码。问题出在类Principal中,根据迪米特法则,只能与直接的朋友发生通信,而Student类并不是Principal类的直接朋友(以局部变量出现的耦合不属于直接朋友),从逻辑上讲校长Principal只与管理者Monitor耦合就行了,可以让Principal继承类Monitor,重写一个printMember的方法。优化后的代码如下:public class Monitor {      public List getAllStudent(){         List list = new ArrayList();         for(int i=0; i<100; i++){             Student student = new Student();             //为每个学生分配个ID             student.setId("学生Id:"+i);             list.add(student);         }         return list;     }      public void printMember() {         List list = this.getAllStudent();         for (Student student : list) {             System.out.println(student.getId());         }     } }  public class Principal extends Monitor {      public List getAllTeacher(){         List list = new ArrayList();         for(int i=0; i<30; i++){             Teacher emp = new Teacher();             //为全校老师按顺序分配一个ID             emp.setId("老师编号"+i);             list.add(emp);         }         return list;     }      public void printMember() {         super.printMember();          for (Teacher teacher : this.getAllTeacher()) {             System.out.println(teacher.getId());         }     } }  复制代码5. 里氏替换原则
  里氏替换原则:
  如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。
  一句话来描述就是:只要有父类出现的地方,都可以用子类来替代,而且不会出现任何错误和异常。 更通俗点讲,就是子类可以扩展父类的功能,但是不能改变父类原有的功能。
  其实,对里氏替换原则的定义可以总结如下:子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法子类中可以增加自己特有的方法当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的的输出/返回值)要比父类的方法更严格或相等
  我们来看个例子: public class Cache {      public void set(String key, String value) {      } }  public class RedisCache extends Cache {      public void set(String key, String value) {      }  } 复制代码
  这里例子是没有违反里氏替换原则的,任何父类、父接口出现的地方子类都可以出现。如果给RedisCache加上参数校验,如下: public class Cache {      public void set(String key, String value) {      } }  public class RedisCache extends Cache {      public void set(String key, String value) {         if (key == null || key.length() < 10 || key.length() > 100) {             System.out.println("key的长度不符合要求");             throw new IllegalArgumentException();         }     } } 复制代码
  这就违反了里氏替换原则了,因为子类方法增加了加了参数校验,抛出了异常,虽然子类仍然可以来替换父类。6.依赖倒置原则
  依赖倒置原则定义:
  高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。它的核心思想是:要面向接口编程,而不要面向实现编程。
  依赖倒置原则可以降低类间的耦合性、提高系统的稳定性、减少并行开发引起的风险、提高代码的可读性和可维护性。要满足依赖倒置原则,我们需要在项目中满足这个规则:每个类尽量提供接口或抽象类,或者两者都具备。变量的声明类型尽量是接口或者是抽象类。任何类都不应该从具体类派生。使用继承时尽量遵循里氏替换原则。
  我们来看一段违反依赖倒置原则的代码,业务需求是:顾客从淘宝购物。代码如下:class Customer{     public void shopping(TaoBaoShop shop){         //购物         System.out.println(shop.buy());     } } 复制代码
  以上代码是存在问题的,如果未来产品变更需求,改为顾客从京东上购物,就需要把代码修改为:class Customer{     public void shopping(JingDongShop shop){         //购物         System.out.println(shop.buy());     } } 复制代码
  如果产品又变更为从天猫购物呢?那有得修改代码了,显然这违反了开闭原则。顾客类设计时,同具体的购物平台类绑定了,这违背了依赖倒置原则。可以设计一个shop接口,不同购物平台(如淘宝、京东)实现于这个接口,即修改顾客类面向该接口编程,就可以解决这个问题了。代码如下:class Customer{     public void shopping(Shop shop){         //购物         System.out.println(shop.buy());     } }  interface Shop{    String buy(); }  Class TaoBaoShop implements Shop{      public String buy(){        return "从淘宝购物";      } }  Class JingDongShop implements Shop{       public String buy(){        return "从京东购物";      } }
  原文:https://juejin.cn/post/7156624841422929933

大促灵感看这篇!编辑部2月爱用大盘点!三八大促前的爱用,想必大家都十分期待吧年后大家也是激情消费了不少好东西,预计又是大型种草现场,这就一起来看看!作为一瓶万能打底精华,兰蔻小黑瓶的优秀不需要赘述,它的功效是需要日积月新皮肤特效在典藏之上?全息碎影完全比不了!没入手血亏!孙悟空跳棍猴瑶组合实战教学兄弟们,年年返场都有猴的秘密破解啦!乍一看猴哥的衣柜确实琳琅满目,但细看会发现能挑的只有地狱火西部大镖客,你说能不年年返场么说到这,过年期间新上线的猴哥齐王者荣耀3。2更新4款皮肤返场,永久皮肤免费送,干将新皮肤上线王者荣耀正式服将在3月2日上午9点开启不停机更新,本次更新的主要内容有1干将莫邪新皮肤上线2充值活动开启34款皮肤返场4永久英雄免费拿5永久皮肤免费送,等等。具体内容如下1干将莫邪世界首次!双光子显微镜获取航天员皮肤三维图像北京日报客户端实习记者何蕊近日,神舟十五号航天员乘组使用由我国自主研制的空间站双光子显微镜,开展在轨验证实验任务并取得成功。这是目前已知的世界首次在航天飞行过程中使用双光子显微镜获白发黑皮肤超模美如黑珍珠,三婚嫁给异瞳摇滚巨星,上演生死恋伊曼是超模舞台上第一个黑人,让美貌跨越了种族歧视,自信美丽的绽放在T台上。在美国原本是以白皮肤作为高贵的存在,起初在模特界选用的模特都是白种人,但是伊曼却打破了这个传统的规矩,用黝1天内,泽连斯基收到2个坏消息,巴赫穆特要丢,武器援助也要没了自去年夏季以来,乌克兰和俄罗斯在巴赫穆特进行了长达半年的激战,双方僵持不下。直到近几个月,俄罗斯派出瓦格纳集团前往巴赫穆特战场,俄方越战越勇,接连拿下巴赫穆特多个城镇和村庄。面对乌通过健康的生活方式,有效调理皮肤干裂和瘙痒!皮肤干裂瘙痒可以有多种原因,以下是一些常见的原因1。天气干燥低湿度和冷空气可能会导致皮肤失去水分,使其变得干燥脱皮瘙痒和发红。2。温度变化突然的温度变化可能会对皮肤产生负面影响,例Gucci最新的灵感缪斯是宁静袁立,金巧巧!看了Gucci2023秋冬大秀,我有一个感受咱天朝明星威武!整场秀就是在致敬我们内娱的经典明星嘛。比如,秀上多次出现薄纱元素。特别是这一套,恕我直言,宁静早就大胆尝试了。早期的男明凌晨转会一天9动态萨拉赫威胁离队,小蜘蛛难续约,C罗募前队友如果夏天红军利物浦没能获得欧冠资格的话,穆罕默德萨拉赫威胁准备离开利物浦,他的去向可能是巴黎圣日耳曼。(Fichajes)AC米兰边锋拉斐尔莱奥被利物浦盯上,红军将准备把路易斯迪亚黄骅记忆新海设治局和新海县的由来设治局是一个官署名,出现在清朝末年,一般是某一个地方预备成立新的县政府之前,总督署巡抚署或省政府可预先成立设治局,用以筹备期间的过渡,主官为设治委员,权限相当于知县(清朝时期)县知来吧,瞅瞅国际庄的一天游!周五的晚上,送完我妞去车站,路上又招朋唤友吃点喝点,喝的迷糊糊的,就定下了周六说走就走的旅行。群里嘚啵嘚啵了一大顿,说好了去石家庄,也没说好去玩啥,一致决定,订好5点的闹钟,出发的
身高成谜!狗仔说易烊千玺175被四字粉怼,网友表示该怼不足170今天,刘大锤说易烊千玺身高175上了热搜1位,狗仔刘大锤跟拍易烊千玺发现四字在拍广告,并且身边人都比他高一头,于是随口来一句瞅小哥差不多1米75左右,这个理由明显站不住脚,于是被四身高不够,裤子来凑!记住少穿这2条,试试另外3款,显瘦显腿长对于大多数的东方女性来说,其实身材最普遍的问题就是下半身臃肿,亚洲女性没有西方女性高挑纤瘦,身高平均也在160左右,所以就要选择更显瘦显腿长的裤装。今天就要跟大家聊一聊裤装的一些挑CBA三消息辽宁外援计划告吹,韩旭6万美元续约,赵维伦身高1米8爱国篮,爱CBA,我是洛姐,小伙伴们看完记得点赞!这个赛季辽宁队的目标肯定是拿到CBA联赛的总冠军,球迷们应该都非常清楚,这是辽宁队最有机会卫冕的一个赛季了,现在CBA联赛即将迎来暴涨12顺位!身高2米03,模板詹姆斯的超级新人,已预定NBA首轮?近日,美国媒体NBADRAFT,更新了2023年的模拟选秀榜单。来自休斯顿大学的小将JaraceWalker,行情出现大幅度上涨。此前绝大多数时候,他被预测只会在首轮末被选中。而最2023儿童身高体重标准公布,118岁都能用,你家孩子达标吗?相信每位家长都知道,孩子的身高发育不是一直在发育的,是一个有时间限制的,当孩子青春期末期,孩子的身高增长空间就已经没剩多少了。所以把握孩子当下的身高是非常重要的,不管孩子的身高现在唠唠我家出生身高仅45cm的佐佑,一路走来的长高打怪秘诀各位友友们好呀!佐佑麻麻又来啦每年一到春天这个万物生机勃发的季节,群里的爸爸妈妈们就总会聊起孩子的生长发育问题。实话实说,在佐佑的成长过程中,我对她俩的智力和语言发育一直都没怎么费身高不到158的女人,穿裤子记得4不要,否则又矮又丑想要让自己的穿搭更加时尚,能够在一众女性面前脱颖而出,那我们就应该牢牢记住扬长避短的穿搭关键,也就是说尽可能通过衣服去遮挡自己的身形缺陷,继而修饰外在的形象。比如,腰腹部赘肉多的女中国乒乓上映,体育片怎样绝地反击才能让体育迷和观众都满意?来源环球时报环球时报特约记者吕克经历多次调档之后,由邓超俞白眉执导的中国乒乓之绝地反击(以下简称中国乒乓,海报如图)终于在2月17日公映。截至19日晚,该片在排片占比不多的情况下,杭州亚运会亚残运会开闭幕式暖场节目分片遴选收官杭州亚运会亚残运会开闭幕式暖场节目分片遴选现场。杭州亚组委供图中新网杭州2月20日电(钱晨菲)20日,记者从杭州亚组委获悉,随着杭州亚运会亚残运会开闭幕式暖场节目杭州宁波舟山专场分重磅发布!2023藏晚节目单来了!今晚2000关注西藏广播电视台西藏日报客户端西藏日报微信公众号西藏发布微信公众号中国西藏新闻网快搜西藏客户端西藏商报微信公众号以及各地市县区融媒体中心锁定精彩我们今晚有约!!!现场全英赛种子名单出炉!梁王扮演种子杀手,凤凰组合靠虚拟排名入围2023年具有百年历史的全英羽毛球公开赛将于3月14日19日在伯明翰举行,组织方既公布了参赛名单后,又公布了种子名单。和其他公开赛不同,全英赛的种子排位采用世界排名和虚拟积分相结合