当前位置: 首页 > 科技观察

本文讲软件设计模式

时间:2023-03-18 22:18:31 科技观察

本文转载自微信公众号《Java极客技术》,作者鸭血范唐。转载本文请联系Java极客技术公众号。在实际的软件编程过程中,代码设计的合理性将直接决定项目的开发复杂度。一个好的设计模型会让你的软件开发过程变得异常顺畅!1.简介1994年,ErichGamma、RichardHelm、RalphJohnson和JohnVlissides合着了一本书,名为DesignPatterns-ElementsofReusableObject-OrientedSoftware(中文译名:DesignPatterns-ReusableObject-OrientedSoftwareElements),其中第一次提到软件开发中设计模式的概念时,四位作者统称为GOF(GangofFour),简称四人帮!书中提到了23种设计模式,可以分为三大类:CreationalPatterns、StructuralPatterns和BehavioralPatterns。当然,随着软件的飞速发展,还有一类我们熟悉的设计模式:J2EE设计模式。首先要跟大家说明一下,设计模式并不是什么新技术,而是很多软件开发者经过长期的摸索总结出来的一套软件设计和开发实践。经验不足的开发人员学习软件设计的一种简单快捷的方法。不BB了,让我们深入了解一下大师们总结的方法论吧!2.方法论2.1、单一职责原则单一职责原则,顾名思义,一个类负责一个功能的处理,比如我们在代码中经常使用到调用第三方接口的时候,我们通常会进行封装一个接口请求方法变成一个http请求的工具类,方便其他调用者调用。单一职责原则的主要目的是将一个功能划分成合适的粒度,让这些各自履行单一职责的类各司其职。还有就是我们常说的mvc模型,将数据操作和业务逻辑处理分开,也是一种单一职责原则。2.2.开闭原则开闭原则是指:对扩展开放,对修改封闭。这里的意思是,在增加新功能的时候,尽量不要不改代码就改代码。如果新功能仅通过添加代码来完成,那是最好的。我举个简单的例子,大家可能就明白了。在实际项目开发过程中,尤其是与第三方公司对接时,例如A公司要求其接口协议进行rsa加密;b公司对其接口协议使用aes加密;公司c要求其接口协议要求使用md5……一开始你可能没想那么多。想象一下,当所有其他公司与您联系时,他们都使用rsa加密。那么当第二家公司来的时候,要求使用aes,这个时候,你就得改代码支持这个功能。如果另一家公司来了怎么办?这种情况下,我们可以采用面向接口编程的思想,定义一个抽象方法,然后针对不同的加密算法,编写不同的实现类,当一个新公司需要不同的加密算法时,我们只需要扩展一个新增实现类,并在逻辑处理层进行路由,快速完成开发对接!实现开闭原则主要是将业务方法中的逻辑进行抽象,从而实现代码在逻辑层面的解耦。2.3.里氏代换原则里氏代换原则,通俗地说就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除了增加新的方法来完成新的功能外,尽量不要重写父类的方法。当子类重写父类的方法时,如果使用不当,很可能改变父类方法中的逻辑语义,造成逻辑处理混乱。在实际业务开发中,尤其是在使用类继承操作时,要谨慎重父方法,定义方法时,名称尽量不要重名。同时要注意类的继承过多。比如A类继承B类,B类继承C类,C类继承D类。这种场景下,第一:逻辑很可能很复杂,代码可读性可能很差,第二可能会出现方法名或属性名冲突。当我修改一个旧的项目bug时,发生了这种情况。实体类具有三层关系继承。当我把子类序列化成json的时候,突然报错了。原因是它有一个属性。也是在基类中定义的,但是类型不同,也就是说这个子类中有两个相同的属性,但是字段类型不同,导致这个序列化错误。因此,在使用类继承操作时,一定要慎重。最好的情况是一层关系继承,这样即使出现问题也容易排查,范围可控;如果继承关系太多,代码就会变得很复杂,每个方法的逻辑都需要一个一个梳理清楚才敢下手。这样的话,就是给自己丢脸了!2.4.依赖倒置原理依赖倒置原理。简单的说就是面向接口的编程,它依赖于抽象而不依赖于具体,他是一种实现开闭原则的方式。依赖倒置原则主要有以下几点:高层模块不应该依赖低层模块,两者都应该依赖于它们的抽象。抽象不应依赖于细节。细节应该依赖于抽象。逻辑抽象提升为接口或抽象类,具体的实现类用于实现具体的业务逻辑。抽象层不注重细节。这就是我们俗称的,不管发生什么事,先看大局,再看小点。比如我们经常使用的MVC框架,在Service层,通常是先写接口类,再写服务实现类。这是典型的面向接口编程。这个解决方案有什么好处?可以降低研发人员的并行度。开发带来的风险可以显着提高代码的可读性和可维护性,降低类之间的耦合度。在开发一个大项目的时候,想象一下,如果有两个以上的开发人员在写同一个类的同一个方法,如果没有定义接口,久而久之这个类很可能会变得很混乱。同时,里面的方法估计很难读懂。一眼看去,基本不可能知道这个方法是干什么的,尤其是那些重要的。当上传方式较多时,尤其困难。我们引入接口之后,所有的核心方法都被抽象定义了。我们在进行二次开发的时候,也可以快速定位到之前的和谐方法,然后快速定位维护。面向接口编程的另一大好处是可以降低类之间的耦合度。2.5.接口隔离原则接口隔离原则的意思是:尽量把一个接口分解成更细的细节,使用多个隔离的接口,这比使用单个接口要好。这个原则基本上是从大规模软件架构的思想中诞生的,易于升级和维护。比如第三方保险服务系统,如果是小项目,可以在一个接口中定义五个方法:投保方法、退保方法、退保方法、理赔方法、保单方法.当你只和一家保险公司合作的时候,这套接口定义是没问题的,但是如果现在公司业务发展很快,引入了10多家保险公司,你会发现这套接口基本站不住脚嘛,这里有两种方法可以解决这个技术问题:针对不同的保险公司重新定义一个接口,然后利用里面的5个方法分别为保险等不同的操作行为定义一套单独的接口,然后为不同的保险公司编写不同的实现类不同的保险公司。这两者其实就是把一个接口拆分成多个更细粒度的接口,然后让各个实现类在行为上更加独立,从而减少类差异。它们之间的耦合程度使得开发层次清晰,有利于系统的稳定!2.6.组合/聚合和复用原则组合和复用原则的意思是:尽量使用组合/聚合而不是继承。所谓组合/聚合方式其实就是我们在springMVC中使用的ioc依赖注入方式,@ComponentpublicclassAService{/***ioc依赖注入*/@AutowiredprivateBServicebService;//业务代码...}AService类BService类有两种调用方式。第一种是通过继承,可以直接调用;第二种方式是通过ioc依赖注入在类中组合操作,然后调用。很显然,第二种方法,我们爱不释手!这种方法的优点是代码层次清晰,文笔优雅,使用后容易上瘾。推荐使用!2.7、迪米特定律迪米特定律,又称为最少知道原则,是指一个实体应尽可能少地与其他实体进行交互,从而使系统的功能模块相对独立。类似于单一原则的思想,比如我们写实体类的时候,基本就是属性名,加上get/set。publicclassUser{/***用户ID*/privateLonguserId;/***用户名*/privateStringuserName;publicLonggetUserId(){returnthis.userId;}publicvoidsetUserId(LonguserId){这个。用户Id=用户Id;}publicStringgetUserName(){returnthis.userName;}publicvoidsetUserName(StringuserName){this.userName=userName;}}当一个实体中有与自身无关的代码,比如数据运算逻辑处理,这时候就应该清理这部分代码,交给业务处理层。从实体类的定义来看,它的主要功能是承担数据展示。当多个业务处理层使用这个实体类时,如果你嵌套了很多数据操作逻辑,客户端可能得到的实体类的属性值不是正确的结果!3.总结以上一共介绍了7条设计原则,基本上是大师们经过多次血的教训总结出来的一套方法论。这些设计原则可以为同事在实际的软件设计过程中提供一些思路。具体应用需要结合实际业务场景进一步考虑。如何让系统更可靠,开发更好更快,代码可读性更好。很简单,关键是要灵活运用!