软件设计原则

目的

高内聚低耦合

内聚

模块内部合理且紧密联系的元素彼此组织在一起完成一个单一的功能。
这样的模块职责单一,边界清晰,功能稳定,可维护性和可复用性强。

耦合

耦合度描述的是模块与模块之间的关联、感知、依赖程度。
耦合度越低则代表模块的独立性越强,模块间的互相影响越小,模块间的互相影响越小,则系统越稳定可靠。
耦合度越高,则系统内部越错综复杂,越容易牵一发而动全身,局部的修改导致大范围的修改,局部的异常甚至引发系统的瘫痪

内聚和耦合的关系

软件涉及力求做到高内聚,低耦合。高内聚是低耦合的基础。

软件结构

可维护性

在不破坏原有代码设计、不引入新的bug 的情况下,能够快速地修改或者添加代码。

可扩展性

在不修改或少量修改原有代码的情况下,可以通过扩展的方式添加新的功能代码。

可复用性

尽量减少编写重复代码,复用已有代码。

面向对象的六大设计原则

单一职责原则

单一职责原则又称单一功能原则,它规定一个类应该只有一个发生变化的原因。

如果需要开发的一个功能需求不是一次性的,且随着业务发展的不断变化而变化,那么当一个Class类负责超过两个及以上的职责时,就在需求的不断迭代、实现类持续扩张的情况下,就会出现难以维护、不好扩展、测试难度大和上线风险高等问题。

所谓的职责就是指类变化的原因,也就是业务需求。如果一个类有多于一个的原因被改变,那么这个类就有超过两个及以上的职责。而单一职责约定一个类应该有且仅有一个改变类的原因。

开闭原则

在面向对象编程领域中,开闭原则规定软件中的对象、类、模块和函数对扩展应该是开放的,但对于修改是封闭的。这意味着应该用抽象定义结构,用具体实现扩展细节,以此确保软件系统开发和维护过程的可靠性。

开闭原则的核心思想也可以理解为面向抽象编程。

里氏替换原则

定义

继承必须确保超类所拥有的性质在子类中仍然成立。

具体方法

如果S是T的子类型,那么所有T类型的对象都可以在不破坏程序的情况下被S类型的对象替换。

简单来说,子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:当子类继承父类时,除添加新的方法且完成新增功能外,尽量不要重写父类的方法。这句话包括了四点含义:

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

作用

  • 里氏替换原则是实现开闭原则的重要方式之一。
  • 解决了继承中重写父类造成的可复用性变差的问题。
  • 是动作正确性的保证,即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。
  • 加强程序的健壮性,同时变更时可以做到非常好的兼容性,提高程序的维护性、可扩展性,降低需求变更时引入的风险。

迪米特法则原则

迪米特法则又称为最少知道原则,是指一个对象类对于其他对象类来说,知道得越少越好。也就是说,两个类之间不要有过多的耦合关系,保持最少关联性。

迪米特法则有一句经典语录:只和朋友通信,不和陌生人说话。也就是说,有内在关联的类要内聚,没有直接关系的类要低耦合。这样的例子在我们生活中也随处可见,就像家里的水管装修,有洗衣机地漏、卫生间地漏、厨房地漏,但它们最终都汇到同一个污水处理系统里。在平常使用时,我们不会考虑这些水管是怎么关联流向的,只需要考虑最上层的使用即可。

如果校长想知道一个班级的总分和平均分,是应该找老师要,还是跟每一个学生要再进行统计呢?显然是应该找具体的班主任老师,校长并不需要知道每个同学的分数。我们在实际开发时,容易忽略这样的真实情况,开发出逻辑错误的程序。

接口隔离原则

客户端不应该被迫依赖于它不使用的方法。该原则还有另外一个定义:一个类对另一个类的依赖应该建立在最小的接口上。

接口隔离原则要求程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含客户感兴趣的方法。

接口隔离是为了高内聚、低耦合。在实际的业务开发中,通常会先定义好需要开发的接口,并由各个服务类实现。但如果没有经过考虑和设计,就很可能造成一个接口中包括众多的接口方法,而这些接口并不一定在每一个类中都需要实现。这样的接口很难维护,也不易于扩展,每一次修改验证都有潜在的风险。

在具体应用接口隔离原则时,应该根据以下几个规则衡量。

  • 接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。
  • 为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。
  • 了解环境,拒绝盲从。每个项目或产品都有选定的环境因素,环境不同,接口拆分的标准就不同,要深入了解业务逻辑。
  • 提高内聚,减少对外交互。让接口用最少的方法完成最多的事情。

依赖倒置原则

依赖倒置原则是指在设计代码架构时,高层模块不应该依赖于底层模块,二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。

依赖倒置原则是实现开闭原则的重要途径之一,它降低了类之间的耦合,提高了系统的稳定性和可维护性,同时这样的代码一般更易读,且便于传承。