合成复用原则(Composite/Aggregate Reuse Principle,CARP)是指尽量使用对象组 合(has-a)/聚合(contanis-a),而不是继承关系达到软件复用的目的。可以使系统更加灵 活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。

继承我们叫做白箱复用,相当于把所有的实现细节暴露给子类。组合/聚合也称之为黑箱 复用,对类以外的对象是无法获取到实现细节的。要根据具体的业务场景来做代码设计, 其实也都需要遵循 OOP 模型。


demo:

文章,数据库操作。两个各自的对象封装。

文章不应该继承数据库类来达到数据的增删改查,而是通过聚合,实例化数据库类来直接使用。当然不同的数据库应该中间有个抽象层,底层有选择来决定调用那个数据库。

任何基类可以出现的地方,子类一定可以出现。里氏替换原则是继承复用的基石,只有当衍生类可以替换基类,软件单位的功能不受到影响时,即基类随便怎么改动子类都不受此影响,那么基类才能真正被复用

这就要求必须以下的规则:

  • 子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。
  • 子类中可以增加自己特有的方法。
  • 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  • 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。


优点:

代码共享,即公共代码被抽到父类。

提高代码重用性。

子类在父类的基础上可以有自己的特性。

提高代码的扩展性。

缺点:

侵入性。一旦继承,父类全部属性和方法都被子类拥有

约束性。子类需要拥有父类的属性和方法,子类多了一些约束。

耦合性。父类出现修改情况时,需要考虑子类的修改。


现实中的demo:

比如你在数据库操作模型中写了一个基类的 查询。理论上这个查询只要继承了这个基类所有models都可以调用,所以子类调用的时候,如果子类重写了该方法并且更改了原来的功能。这个继承就变得不在有意义。


定义:

又叫最少知道原则,如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。

作用:

其目的是降低类之间的耦合度,提高模块的相对独立性。

反作用:

增加了系统的复杂度

定义:

高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。

作用:

依赖倒置原则可以降低类间的耦合性;

依赖倒置原则可以提高系统的稳定性;

依赖倒置原则可以减少并行开发引起的风险;

依赖倒置原则可以提高代码的可读性和可维护性;

demo:

员工A 要给 员工B发送消息通知

最开始,我们发送消息的方法用的是通过邮件发送。发送动作是高层模块,邮件发送是底层模块。当有一天邮件模块不可用了,需要通过短信发送。 这个适合 原来高层模块无法发送。因为不支持短信。要是直接改邮件发送模块很显然不是对的。

优化方案:

中间加一层发送的抽象类接口。 高级发送模块只需要依赖与这个抽象类,而底层模块也应该依赖于这个抽象类。当更改了发送方案的情况下,只需要让不同的抽象类调用底层的发送接口即可。




定义:

接口隔离原则(Interface Segregation Principle,ISP)的定义是客户端不应该依赖它不需要的接口,类间的依赖关系应该建立在最小的接口上。简单来说就是建立单一的接口,不要建立臃肿庞大的接口。也就是接口尽量细化,同时接口中的方法尽量少。
接口隔离原则必须先满足单一原则。这里的接口单一指的是业务上的接口单一,单一原则指的是职责上的单一。

特点:

将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。


  • 如果把“接口”理解为一组接口集合,可以是某个微服务的接口,也可以是类库的接口等。如果部分接口只被部分调用者使用,我们就需要将这部分接口隔离出来,单独给这部分调用者使用,而不强迫其他调用者也依赖这部分不会被用到的接口。
  • 如果把“接口”理解为单个API接口或函数,部分调用者只需要函数中的部分功能,那我们就需要把函数拆分成粒度更细的多个函数,让调用者只依赖它需要的那个细粒度函数。
  • 如果把“接口”理解为OOP中的接口,也可以理解为面向对象编程语言中的接口语法。那接口的设计要尽量单一,不要让接口的实现类和调用者,依赖不需要的接口函数。

单一职责原则;

接口隔离原则;

依赖倒置原则;

里氏替换原则;

开闭原则;

迪米特法则;

合成复用原则;

口诀

何旦 - 开迪 - 接 - 李依

合单 - 开迪 - 接 - 里依


概念

一个类应该只负责一个职责,当一个类同时负责多个职责的时候,某个职责发生变动可能会影响整个类或者其他类的使用。

实际开发中,应该是尽量一个类只负责一个职责。同样一个方法,函数也应该只负责某项功能。

特点:

降低类(代码)的复杂度;

降低变更引起的风险;

减少影响范围,系统更稳定。

demo:

比如订单类应该只处理跟订单相关逻辑,而不要处理和用户相关的逻辑。

比如在laravel model开发中,user 的model应该只有跟用户相关的处理,不同的对象应该创建不同的model;

比如控制器,同对象的控制器可以用一个控制器,而不要所有的逻辑都到一个控制器去处理;