一、单一职责原则

1.1> 名词解释

SRP:单一职责(Single Reposibility Principle)

RBAC:基于角色的访问控制(Role-Based Access Control)

1.2> 定义

一个类或者模块只负责完成一个职责。

1.3> 最佳实践

接口设计一定要尽量做到单一职责。

类的设计不应该大而全,要设计粒度小、功能单一的类。如果一个类中存在多个不相干的功能,那么我们就违背了单一职责原则,应该将它拆分成多个功能单一、粒度更新的类。如下图所示:

设计原则有哪些?什么是里式替换原则?_后端

  • 每个电脑组件各司其职。如果要升级,可以针对某一模块组件升级,而不用影响到整台电脑。
  • 而且是基于接口开发,可以扩展更换不同的实现类。

二、里氏替换原则

2.1> 名词解释

LSP:里式替换原则(Liskov Substitution Principle)

2.2> 定义

LSP的原定义比较复杂,我们一般对里氏替换原则LSP的解释为:子类对象能够替换父类对象,而程序逻辑不变。继承必须确保父类所拥有的性质在子类中仍然成立

继承的优点:

  • 提高代码的重用性,子类拥有父类的方法和属性;
  • 提高代码的可扩展性,子类可形似于父类,但异于父类,保留自我的特性;

继承的缺点:

  • 继承是侵入性的,只要继承就必须拥有父类的所有方法和属性,在一定程度上约束了子类,降低了代码的灵活性;
  • 增加了耦合,当父类的常量、变量或者方法被修改了,需要考虑子类的修改,所以一旦父类有了变动,很可能会造成非常糟糕的结果,要重构大量的代码。

任何基类可以出现的地方,子类一定可以出现。里氏替换原则是继承复用的基石,只有当衍生类可以替换基类,软件单位的功能不受到影响时,即基类随便怎么改动子类都不受此影响(即:子类可以拥有父类[非接口or抽象类]的方法,但是不要重写父类的方法),那么基类才能真正被复用。因为继承带来的侵入性,增加了耦合性,也降低了代码灵活性,父类修改代码,子类也会受到影响,此时就需要里氏替换原则。

里氏替换原则有至少以下两种含义:

1> 里氏替换原则是针对继承而言的,如果继承是为了实现【代码重用】,也就是为了共享方法,那么共享的父类方法就应该保持不变,不能被子类重新定义。子类只能通过新添加方法来扩展功能,父类和子类都可以实例化,而子类继承的方法和父类是一样的,父类调用方法的地方,子类也可以调用同一个继承得来的,逻辑和父类一致的方法,这时用子类对象将父类对象替换掉时,当然逻辑一致,相安无事。

子类重写了父类,那么当父类被重写的方法发生了变动(比如:里面加入了鉴权方法),那么子类的重写方法没有鉴权,则会出现问题。(高耦合)

  • 2> 如果继承的目的是为了【多态】,而多态的前提就是子类覆盖并重新定义父类的方法,为了符合LSP,我们应该将父类定义为抽象类,并定义抽象方法,让子类重新定义这些方法,当父类是抽象类时,父类就是不能实例化,所以也不存在可实例化的父类对象在程序里。也就不存在子类替换父类实例(根本不存在父类实例了)时逻辑不一致的可能。

在实际应用中,里氏替换可以表现出如下四种情况:

  • 1> 子类必须完全实现父类的方法

有一个WarGun的接口或抽象类,用来描述战场枪支,里面有kill()方法,来描述枪支的杀伤力,其子类AK47AWMM416都实现了kill()方法,但是ToyGun因为是玩具枪,它没有杀伤力,所以,无法实现kill(),那么针对这种情况,即:子类不能完整的实现父类的方法,或者父类的某些方法在子类中已经发生了“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承

  • 2> 子类中可以增加自己特有的方法,即:子类可以有自己的个性。
  • 3> 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松

如果父类方法为doSomething(Map map),子类方法为doSomething(HashMap map),那么由于方法签名不同,其实不是重写而是重载了。那么当入参为HashMap时,调用父类对象的doSomething方法,则执行了父类的方法。调用子类的doSomething方法,则执行了子类。那么,这种情况下,我们往往会以为,调用的都是父类的doSomething。

  • 4> 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格,编译上也会提示有问题

2.3> 最佳实践

不符合LSP的最常见的情况是,父类和子类都是可实例化的非抽象类,且父类的方法被子类重新定义,这一类的实现继承会造成父类和子类间的强耦合,也就是实际上并不相关的属性和方法牵强附会在一起,不利于程序扩展和维护。

如何符合LSP?总结一句话 —— 就是尽量不要从可实例化的父类中继承,而是要使用基于抽象类和接口的继承

2.4> Java中的函数签名

方法签名的组成:

1> 方法名
2> 参数列表(形参类别、个数、顺序)

特别注意:

1> 与返回值、修饰符以及异常无关
2> 在Class文件格式之中,返回值不同,可以合法地共存于一个Class文件中。
3> 在泛型的使用中,参数List与List在经过类型擦除后,是相同参数。
4> 参数String... strings与参数String[] arr,是相同参数

重载和重写

重载:同一个类中方法签名不同的方法。
重写:方法签名必定相同,返回值必定相同, 访问修饰符 "子 > 父", 异常类 "子 < 父"

三、依赖倒置原则

3.1> 名词解释

DIP:依赖倒置原则(Dependence Inversion Principle)

3.2> 定义

下层模块引入上层模块的依赖,改变原有自上而下的依赖方向。要面向接口编程,不要面向实现编程。

3.3> 最佳实践

3.3.1> 针对于类直接的依赖

讲一个故事:建国初期,国家要培养一批出租车司机。那么需要会开车的人和汽车。那么,为了市容市貌,最初规定,汽车只能是大众生产的捷达汽车,并且喷上某种代表出租车的配色即可。期初需求不大,培养出1万出租车司机即可。随着国家富强了,很多二三四线城市也要培养出租车司机,那么对于汽车的订单量就大大提升了,第二年全国需要培养30万名出租车司机。但是德国大众集团每年针对捷达汽车的产量只有2万台,所以,明年培养30万名出租车司机的需求就无法实现了。因为我们严重的依赖了下游的德国大众公司。那么,针对这种情况,国家出台了新的政策。出租车司机,不是必须只能开大众捷达汽车了。只要作为出租车的汽车满足一定的规定要求即可。比如:四门四座、油耗、安全性、安装计费设备等等。那么,其他的汽车品牌,比如:现代、本田、丰田、比亚迪等等,为了抢占这块市场,纷纷按照国家出台的出租车标准,生产了一系列的轿车。那么,总的汽车产能一下子就满足要求了。

我们发现没有,解决这个问题的关键就是——依赖方向变化了(产生了依赖的倒置)。

从最初的依赖具体对象:
国家(上游)——>依赖——>大众集团公司(下游)

变为了依赖接口规范:
大众和其他汽车品牌集团公司(下游)——>依赖——>国家出台的出租汽车标准(上游)

3.3.2> 针对于项目模块的依赖

图如下所示:

设计原则有哪些?什么是里式替换原则?_后端_02

四、接口隔离原则

4.1> 定义

建立单一接口,不要建立臃肿庞大的接口。接口尽量细化,同时接口中的方法尽量少。

单一职责原则和接口隔离的区别? 它们的审视角度不同

  • 单一职责要求的是类和接口职责单一,注重的是职责,这是业务逻辑上的划分。
  • 接口隔离原则要求接口的方法尽量少

如何保证接口的纯洁性?

1> 接口要尽量小

  • 不要违反单一职责原则。
  • 要适度的小。要适度。

2> 接口要高内聚

  • 提高接口、类、模块的处理能力,减少对外的交互。

3> 定制服务

  • 通过对高质量接口的组装,实现服务的定制化。
五、迪米特法则/最少知识原则

5.1> 名词解释

LoD:迪米特法则(Law of Demeter)。

5.2> 定义

迪米特法则,也称为最少知识原则

描述的是:一个类应该对自己需要耦合或调用的类知道得最少,你(被耦合或调用的类)的内部是如何复杂,那是你的事儿,和我没关系,我就知道你提供的这么多public方法,我就调用这么多,其他的我一概不关系。

当一个微信用户要在我们系统操作业务逻辑的时候,我们的需求是,如果微信用户没有注册我们系统的话,我们默认的调用注册接口去注册它,注册成功后,把用户信息返回给业务系统;如果她已经注册了,即已经存在于我们的用户表,则把用户信息返回给业务系统,再通过它的用户信息,进行下一步业务操作。那么针对于这个需求,我们其实应该是希望负责用户信息的研发团队,给我们提供一个接口,即:获得用户信息的接口。而不应该提供用户信息查询接口,用户信息注册接口,甚至底层还涉及到其他安全性接口,由我们一步一步的去调用。这样就违反了迪米特法则了。

类似DDD里面领域划分的概念。是我域负责的业务我负责,不是我域的业务,对应想关域负责。

六、开闭原则

6.1> 定义

类、方法、模块应该对扩展开放,对修改关闭

通俗讲:添加一个功能应该是在已有的代码基础上进行扩展,而不是修改已有的代码。

6.2> 最佳实践

活动积分功能,如下图所示:

设计原则有哪些?什么是里式替换原则?_子类_03

通过扩展配置,或者扩展原有接口的方式,应对新的需求变更。现实中,还是很难实现完全开闭原则的,但是我们在开发设计中,应该贯彻这种思想。

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的点赞&分享

更多技术干货,欢迎大家关注公众号“爪哇缪斯” \~ (^o^) /~ 「干货分享,每周更新」