设计模式之设计原则

写在前面的话

从今天开始,我要每天学习一点设计模式。其实设计模式的书我之前就看过,而且不止一遍,不过阅读是一回事,理解又是另一回事。这次我决定把每次的学习,实践全都记录下来,一方面可以加深理解,另一方面也可以强制自己动手实践,我争取保证每种设计模式都要有理解,编码和UML三方面的内容记录,为了防止偷懒,每天写博客打卡记录。
现在说到设计模式,普遍指的就是四人帮总结的23种设计模式,每天学一种,尚且需要学习将近一个月,所以要抓紧时间,随着开发经验的积累,我觉得这次我会有新的理解和感受,第一篇博客,先看一下六大设计原则。

六大设计原则是什么

23种设计模式其实都是围绕着六种设计原则来设计的的,它们分别是单一职责原则,里氏替换原则,依赖倒置原则,接口隔离原则,迪米特法则和开闭原则。这六种设计原则是设计模式的基础,下面逐一来看。

单一职责原则SRP

单一职责原则(Single Responsiblity Principle):一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。

从字面上看很简单,它的作用也是显而易见的,试想,如果有一个功能需要修改,只需要调整该功能所对应的类即可,不会影响到其它部分代码的实现,遵循单一职责原则可以把业务变更带来的风险降至最低。

但是,在实际开发过程中,真正意义上遵循单一职责原则的例子却很少见,实际开发中,需要考虑到结构复杂度等等问题,过分的细化会造成类的数量不断增多,更多的时候在方法级别满足单一职责原则就够了。单一职责原则是是实现高内聚、低耦合的指导方针,体现了模块化编程的思想。

里氏替换原则LSP

里氏替换原则(Liskov Substitution Principle):所有引用基类(父类)的地方必须能透明地使用其子类的对象。

该设计原则由2008年图灵奖得主、美国第一位计算机科学女博士Barbara Liskov教授和卡内基·梅隆大学Jeannette Wing教授于1994年提出,也因此得名。这条设计原则针对的是面向对象中非常重要的一大特性–继承。

继承有很多优点,可以代码扩展,增强复用性,提高代码可扩展性等等。但是随之而来也带来了很多问题,继承是侵入性的,使用继承会限制代码的灵活性同时增加了代码的耦合程度,显然这不是我们想要的。所以《Effective Java》中提到了很重要的一点:组合优于继承。

那么应该如何使用好继承呢,里氏替换原则提供了几个方面的限制:

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

只有遵守里氏替换原则,当有需要的时候,只声明其基类,实现换做任何一个之类都能够不影响代码运行,这样代码的扩展性和可维护性才会更好。

依赖倒置原则DIP

依赖倒置原则(Dependence Inversion Principle):高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。

依赖倒置原则体现了面向对象编程的一个核心思想–面向接口编程。考虑到复杂多变的业务场景,很多时候同一功能极有可能会变更实现方式。如果按照传统的思维方式,我们直接把具体的某一种实现逻辑写到程序中去,一旦有变更,那么整个程序都需要全部重写。面向实现编程带来的最大影响就是代码之间耦合度极高,变更代码带来的风险极大。

此时,我们需要一种接触实现类之间耦合的方式,java中接口的概念就是解决这种问题的。一件事物的抽象形式是固定的,而事物之间的依赖可以通过抽象来确定,基于此,我们在这些固定不变的东西上建立依赖关系,而具体的实现遵从里氏替换原则,就可以保证实现类的变化不会影响各级关系依赖。面向接口编程是解耦的一种重要手段。

接口隔离原则ISP

接口隔离原则(Interface Segregation Principle):客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。

接口隔离原则限制了接口的滥用。具体的实现是受接口限制的,一旦接口过大,实现者就必须要为其所有的方法做出实现,然而有些时候,这样会造成很多没必要的东西。接口设计出来应该是做该做的事,复杂的业务其实可以拆分,把所有的东西都放到同一个接口里面其实降低了系统的灵活程度。所以接口要尽量小,至于小到什么程度,肯定不能无限小下去,在满足单一职责的前提下接口可以不用再拆分。不要忘了所有的设计都是为了更好的实现业务,提高接口的内聚性,这样设计才有意义。

迪米特法则LoD

迪米特法则(Law of Demete):又叫作最少知道原则(Least Knowledge Principle 简写LKP),就是指一个对象应当对其他对象有尽可能少的了解。

迪米特法则限制了系统之间的联系。因为我们都知道,类之间联系越大,耦合度越高,一旦修改带来的影响就越大,迪米特法则要求只与直接的朋友通信,朋友包括以下几种:

  • 当前对象本身(this)
  • 以参数形式传入到当前对象方法中的对象
  • 当前对象的成员对象
  • 如果当前对象的成员对象是一个集合,那么集合中的元素也都是朋友
  • 当前对象所创建的对象

除此之外,所有的对象都是陌生人,不能直接通信。这种限制强制了代码间的解耦,要求非朋友之间通信都要使用中介来完成。但是这种做法不一定是完全对的,最大的问题就在于一旦特别复杂,就会产生大量的传递类使系统变得庞大。对于迪米特法则,应用时候一定要权衡一下,既要做到结构清晰,又要高内聚低耦合。

开闭原则OCP

开闭原则(Open Closed Principle):一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

开闭原则是面向对象设计中最基础的设计原则,在六种设计原则中它的定义最模糊,但是会发现实际上其余五种原则乃至23种设计模式无一不是遵守开闭原则。开闭原则中说不出来什么具体的东西,不过在软件开发的任何阶段都要记得开闭原则。我们尽可能的少修改代码,多扩充代码,就是为了使系统能更稳定地适应各种各样的变化。


六种设计原则首字母开头的单词是solid(稳定的),设计出稳定灵活健壮的程序,是学习设计模式的最终目的,后面的23种设计模式都围绕着这六种设计原则。

-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!